Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the coreboot project. |
| 3 | * |
| 4 | * Copyright 2015 Google, Inc. |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by |
| 8 | * the Free Software Foundation; version 2 of the License. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the Free Software |
| 17 | * Foundation, Inc. |
| 18 | */ |
| 19 | |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 20 | #include <assets.h> |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 21 | #include <cbfs.h> |
Aaron Durbin | 09560fa | 2015-05-12 16:43:10 -0500 | [diff] [blame] | 22 | #include <cbmem.h> |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 23 | #include <console/console.h> |
Aaron Durbin | 09560fa | 2015-05-12 16:43:10 -0500 | [diff] [blame] | 24 | #include <rmodule.h> |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 25 | #include <rules.h> |
| 26 | #include <string.h> |
| 27 | #include "misc.h" |
Aaron Durbin | 4e50cdd | 2015-05-15 23:25:46 -0500 | [diff] [blame] | 28 | #include "../vboot_handoff.h" |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 29 | #include "../symbols.h" |
| 30 | |
| 31 | /* The stage loading code is compiled and entered from multiple stages. The |
| 32 | * helper functions below attempt to provide more clarity on when certain |
| 33 | * code should be called. */ |
| 34 | |
| 35 | static int verification_should_run(void) |
| 36 | { |
| 37 | if (ENV_VERSTAGE && IS_ENABLED(CONFIG_SEPARATE_VERSTAGE)) |
| 38 | return 1; |
| 39 | |
| 40 | if (!IS_ENABLED(CONFIG_SEPARATE_VERSTAGE)) { |
| 41 | if (ENV_ROMSTAGE && |
| 42 | IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE)) |
| 43 | return 1; |
| 44 | if (ENV_BOOTBLOCK && |
| 45 | IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK)) |
| 46 | return 1; |
| 47 | } |
| 48 | |
| 49 | return 0; |
| 50 | } |
| 51 | |
| 52 | static int verstage_should_load(void) |
| 53 | { |
| 54 | if (!IS_ENABLED(CONFIG_SEPARATE_VERSTAGE)) |
| 55 | return 0; |
| 56 | |
| 57 | if (ENV_ROMSTAGE && IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE)) |
| 58 | return 1; |
| 59 | |
| 60 | if (ENV_BOOTBLOCK && IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK)) |
| 61 | return 1; |
| 62 | |
| 63 | return 0; |
| 64 | } |
| 65 | |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 66 | static int vboot_active(struct asset *asset) |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 67 | { |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 68 | int run_verification; |
| 69 | |
| 70 | run_verification = verification_should_run(); |
| 71 | |
| 72 | if (run_verification) { |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 73 | verstage_main(); |
| 74 | } else if (verstage_should_load()) { |
Aaron Durbin | 37a5d15 | 2015-09-17 16:09:30 -0500 | [diff] [blame] | 75 | struct cbfsf file; |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 76 | struct prog verstage = |
| 77 | PROG_INIT(ASSET_VERSTAGE, |
| 78 | CONFIG_CBFS_PREFIX "/verstage"); |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 79 | |
Aaron Durbin | ce2c50d | 2015-05-13 13:33:27 -0500 | [diff] [blame] | 80 | printk(BIOS_DEBUG, "VBOOT: Loading verstage.\n"); |
| 81 | |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 82 | /* load verstage from RO */ |
Aaron Durbin | 37a5d15 | 2015-09-17 16:09:30 -0500 | [diff] [blame] | 83 | if (cbfs_boot_locate(&file, prog_name(&verstage), NULL)) |
| 84 | die("failed to load verstage"); |
| 85 | |
| 86 | cbfs_file_data(prog_rdev(&verstage), &file); |
| 87 | |
| 88 | if (cbfs_prog_stage_load(&verstage)) |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 89 | die("failed to load verstage"); |
| 90 | |
| 91 | /* verify and select a slot */ |
| 92 | prog_run(&verstage); |
| 93 | |
| 94 | /* This is not actually possible to hit this condition at |
| 95 | * runtime, but this provides a hint to the compiler for dead |
| 96 | * code elimination below. */ |
| 97 | if (!IS_ENABLED(CONFIG_RETURN_FROM_VERSTAGE)) |
| 98 | return 0; |
| 99 | } |
| 100 | |
| 101 | /* Fill in vboot handoff structure before moving to ramstage so all |
| 102 | * downstream users have access to vboot results. */ |
| 103 | if (ENV_ROMSTAGE) |
| 104 | vboot_fill_handoff(); |
| 105 | |
Aaron Durbin | b5a20b2 | 2015-10-06 17:29:03 -0500 | [diff] [blame] | 106 | return vboot_is_slot_selected(); |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 107 | } |
| 108 | |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 109 | static int vboot_locate_by_components(const struct region_device *fw_main, |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 110 | struct asset *asset) |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 111 | { |
Aaron Durbin | 4e50cdd | 2015-05-15 23:25:46 -0500 | [diff] [blame] | 112 | struct vboot_components *fw_info; |
| 113 | size_t metadata_sz; |
| 114 | size_t offset; |
| 115 | size_t size; |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 116 | struct region_device *fw = asset_rdev(asset); |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 117 | int fw_index = 0; |
| 118 | |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 119 | if (asset_type(asset) == ASSET_ROMSTAGE) |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 120 | fw_index = CONFIG_VBOOT_ROMSTAGE_INDEX; |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 121 | else if (asset_type(asset) == ASSET_RAMSTAGE) |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 122 | fw_index = CONFIG_VBOOT_RAMSTAGE_INDEX; |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 123 | else if (asset_type(asset) == ASSET_PAYLOAD) |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 124 | fw_index = CONFIG_VBOOT_BOOT_LOADER_INDEX; |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 125 | else if (asset_type(asset) == ASSET_REFCODE) |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 126 | fw_index = CONFIG_VBOOT_REFCODE_INDEX; |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 127 | else if (asset_type(asset) == ASSET_BL31) |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 128 | fw_index = CONFIG_VBOOT_BL31_INDEX; |
| 129 | else |
| 130 | die("Invalid program type for vboot."); |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 131 | |
Aaron Durbin | 4e50cdd | 2015-05-15 23:25:46 -0500 | [diff] [blame] | 132 | metadata_sz = sizeof(*fw_info); |
| 133 | metadata_sz += MAX_PARSED_FW_COMPONENTS * sizeof(fw_info->entries[0]); |
| 134 | |
| 135 | fw_info = rdev_mmap(fw_main, 0, metadata_sz); |
| 136 | |
| 137 | if (fw_info == NULL) { |
| 138 | printk(BIOS_INFO, "No component metadata.\n"); |
Aaron Durbin | b6981c0 | 2015-05-15 15:57:51 -0500 | [diff] [blame] | 139 | return -1; |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 140 | } |
| 141 | |
Aaron Durbin | 4e50cdd | 2015-05-15 23:25:46 -0500 | [diff] [blame] | 142 | if (fw_index >= fw_info->num_components) { |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 143 | printk(BIOS_INFO, "invalid index: %d\n", fw_index); |
Aaron Durbin | 4e50cdd | 2015-05-15 23:25:46 -0500 | [diff] [blame] | 144 | rdev_munmap(fw_main, fw_info); |
| 145 | return -1; |
| 146 | } |
Aaron Durbin | b6981c0 | 2015-05-15 15:57:51 -0500 | [diff] [blame] | 147 | |
Aaron Durbin | 4e50cdd | 2015-05-15 23:25:46 -0500 | [diff] [blame] | 148 | offset = fw_info->entries[fw_index].offset; |
| 149 | size = fw_info->entries[fw_index].size; |
| 150 | rdev_munmap(fw_main, fw_info); |
Aaron Durbin | b6981c0 | 2015-05-15 15:57:51 -0500 | [diff] [blame] | 151 | |
Aaron Durbin | 4e50cdd | 2015-05-15 23:25:46 -0500 | [diff] [blame] | 152 | if (rdev_chain(fw, fw_main, offset, size)) { |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 153 | printk(BIOS_INFO, "invalid offset or size\n"); |
Aaron Durbin | b6981c0 | 2015-05-15 15:57:51 -0500 | [diff] [blame] | 154 | return -1; |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 155 | } |
| 156 | |
Aaron Durbin | b6981c0 | 2015-05-15 15:57:51 -0500 | [diff] [blame] | 157 | return 0; |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 158 | } |
| 159 | |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 160 | static int vboot_locate_by_multi_cbfs(const struct region_device *fw_main, |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 161 | struct asset *asset) |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 162 | { |
Aaron Durbin | 37a5d15 | 2015-09-17 16:09:30 -0500 | [diff] [blame] | 163 | struct cbfsf file; |
| 164 | |
| 165 | if (cbfs_locate(&file, fw_main, asset_name(asset), NULL)) |
| 166 | return -1; |
| 167 | |
| 168 | cbfs_file_data(asset_rdev(asset), &file); |
| 169 | |
| 170 | return 0; |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 171 | } |
| 172 | |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 173 | static int vboot_asset_locate(const struct region_device *fw_main, |
| 174 | struct asset *asset) |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 175 | { |
| 176 | if (IS_ENABLED(CONFIG_MULTIPLE_CBFS_INSTANCES)) |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 177 | return vboot_locate_by_multi_cbfs(fw_main, asset); |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 178 | else |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 179 | return vboot_locate_by_components(fw_main, asset); |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 180 | } |
| 181 | |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 182 | /* This function is only called when vboot_active() returns 1. That |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 183 | * means we are taking vboot paths. */ |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 184 | static int vboot_locate(struct asset *asset) |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 185 | { |
Aaron Durbin | 4e50cdd | 2015-05-15 23:25:46 -0500 | [diff] [blame] | 186 | struct region_device fw_main; |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 187 | |
| 188 | /* Code size optimization. We'd never actually get called under the |
| 189 | * followin cirumstances because verstage was loaded and ran -- never |
| 190 | * returning. */ |
| 191 | if (verstage_should_load() && !IS_ENABLED(CONFIG_RETURN_FROM_VERSTAGE)) |
| 192 | return 0; |
| 193 | |
Aaron Durbin | b5a20b2 | 2015-10-06 17:29:03 -0500 | [diff] [blame] | 194 | if (vb2_get_selected_region(&fw_main)) |
Aaron Durbin | 4e50cdd | 2015-05-15 23:25:46 -0500 | [diff] [blame] | 195 | die("failed to reference selected region\n"); |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 196 | |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 197 | return vboot_asset_locate(&fw_main, asset); |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 198 | } |
| 199 | |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 200 | const struct asset_provider vboot_provider = { |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 201 | .name = "VBOOT", |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 202 | .is_active = vboot_active, |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 203 | .locate = vboot_locate, |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 204 | }; |