blob: bb7bc4c8287c5b2848193cf476db060e439d881e [file] [log] [blame]
Aaron Durbin17200ad2015-05-01 16:48:54 -05001/*
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 Durbinac12c66c2015-05-20 12:08:55 -050020#include <assets.h>
Aaron Durbin17200ad2015-05-01 16:48:54 -050021#include <cbfs.h>
Aaron Durbin09560fa2015-05-12 16:43:10 -050022#include <cbmem.h>
Aaron Durbin17200ad2015-05-01 16:48:54 -050023#include <console/console.h>
Aaron Durbin09560fa2015-05-12 16:43:10 -050024#include <rmodule.h>
Aaron Durbin17200ad2015-05-01 16:48:54 -050025#include <rules.h>
26#include <string.h>
27#include "misc.h"
Aaron Durbin4e50cdd2015-05-15 23:25:46 -050028#include "../vboot_handoff.h"
Aaron Durbin17200ad2015-05-01 16:48:54 -050029#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
35static 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
52static 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 Durbinac12c66c2015-05-20 12:08:55 -050066static int vboot_active(struct asset *asset)
Aaron Durbin17200ad2015-05-01 16:48:54 -050067{
Aaron Durbin17200ad2015-05-01 16:48:54 -050068 int run_verification;
69
70 run_verification = verification_should_run();
71
72 if (run_verification) {
Aaron Durbin17200ad2015-05-01 16:48:54 -050073 verstage_main();
74 } else if (verstage_should_load()) {
Aaron Durbin37a5d152015-09-17 16:09:30 -050075 struct cbfsf file;
Aaron Durbinac12c66c2015-05-20 12:08:55 -050076 struct prog verstage =
77 PROG_INIT(ASSET_VERSTAGE,
78 CONFIG_CBFS_PREFIX "/verstage");
Aaron Durbin17200ad2015-05-01 16:48:54 -050079
Aaron Durbince2c50d2015-05-13 13:33:27 -050080 printk(BIOS_DEBUG, "VBOOT: Loading verstage.\n");
81
Aaron Durbin17200ad2015-05-01 16:48:54 -050082 /* load verstage from RO */
Aaron Durbin37a5d152015-09-17 16:09:30 -050083 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 Durbin17200ad2015-05-01 16:48:54 -050089 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 Durbinb5a20b22015-10-06 17:29:03 -0500106 return vboot_is_slot_selected();
Aaron Durbin17200ad2015-05-01 16:48:54 -0500107}
108
Aaron Durbin899d13d2015-05-15 23:39:23 -0500109static int vboot_locate_by_components(const struct region_device *fw_main,
Aaron Durbinac12c66c2015-05-20 12:08:55 -0500110 struct asset *asset)
Aaron Durbin17200ad2015-05-01 16:48:54 -0500111{
Aaron Durbin4e50cdd2015-05-15 23:25:46 -0500112 struct vboot_components *fw_info;
113 size_t metadata_sz;
114 size_t offset;
115 size_t size;
Aaron Durbinac12c66c2015-05-20 12:08:55 -0500116 struct region_device *fw = asset_rdev(asset);
Aaron Durbin899d13d2015-05-15 23:39:23 -0500117 int fw_index = 0;
118
Aaron Durbinac12c66c2015-05-20 12:08:55 -0500119 if (asset_type(asset) == ASSET_ROMSTAGE)
Aaron Durbin899d13d2015-05-15 23:39:23 -0500120 fw_index = CONFIG_VBOOT_ROMSTAGE_INDEX;
Aaron Durbinac12c66c2015-05-20 12:08:55 -0500121 else if (asset_type(asset) == ASSET_RAMSTAGE)
Aaron Durbin899d13d2015-05-15 23:39:23 -0500122 fw_index = CONFIG_VBOOT_RAMSTAGE_INDEX;
Aaron Durbinac12c66c2015-05-20 12:08:55 -0500123 else if (asset_type(asset) == ASSET_PAYLOAD)
Aaron Durbin899d13d2015-05-15 23:39:23 -0500124 fw_index = CONFIG_VBOOT_BOOT_LOADER_INDEX;
Aaron Durbinac12c66c2015-05-20 12:08:55 -0500125 else if (asset_type(asset) == ASSET_REFCODE)
Aaron Durbin899d13d2015-05-15 23:39:23 -0500126 fw_index = CONFIG_VBOOT_REFCODE_INDEX;
Aaron Durbinac12c66c2015-05-20 12:08:55 -0500127 else if (asset_type(asset) == ASSET_BL31)
Aaron Durbin899d13d2015-05-15 23:39:23 -0500128 fw_index = CONFIG_VBOOT_BL31_INDEX;
129 else
130 die("Invalid program type for vboot.");
Aaron Durbin17200ad2015-05-01 16:48:54 -0500131
Aaron Durbin4e50cdd2015-05-15 23:25:46 -0500132 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 Durbinb6981c02015-05-15 15:57:51 -0500139 return -1;
Aaron Durbin17200ad2015-05-01 16:48:54 -0500140 }
141
Aaron Durbin4e50cdd2015-05-15 23:25:46 -0500142 if (fw_index >= fw_info->num_components) {
Aaron Durbin899d13d2015-05-15 23:39:23 -0500143 printk(BIOS_INFO, "invalid index: %d\n", fw_index);
Aaron Durbin4e50cdd2015-05-15 23:25:46 -0500144 rdev_munmap(fw_main, fw_info);
145 return -1;
146 }
Aaron Durbinb6981c02015-05-15 15:57:51 -0500147
Aaron Durbin4e50cdd2015-05-15 23:25:46 -0500148 offset = fw_info->entries[fw_index].offset;
149 size = fw_info->entries[fw_index].size;
150 rdev_munmap(fw_main, fw_info);
Aaron Durbinb6981c02015-05-15 15:57:51 -0500151
Aaron Durbin4e50cdd2015-05-15 23:25:46 -0500152 if (rdev_chain(fw, fw_main, offset, size)) {
Aaron Durbin899d13d2015-05-15 23:39:23 -0500153 printk(BIOS_INFO, "invalid offset or size\n");
Aaron Durbinb6981c02015-05-15 15:57:51 -0500154 return -1;
Aaron Durbin17200ad2015-05-01 16:48:54 -0500155 }
156
Aaron Durbinb6981c02015-05-15 15:57:51 -0500157 return 0;
Aaron Durbin17200ad2015-05-01 16:48:54 -0500158}
159
Aaron Durbin899d13d2015-05-15 23:39:23 -0500160static int vboot_locate_by_multi_cbfs(const struct region_device *fw_main,
Aaron Durbinac12c66c2015-05-20 12:08:55 -0500161 struct asset *asset)
Aaron Durbin899d13d2015-05-15 23:39:23 -0500162{
Aaron Durbin37a5d152015-09-17 16:09:30 -0500163 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 Durbin899d13d2015-05-15 23:39:23 -0500171}
172
Aaron Durbinac12c66c2015-05-20 12:08:55 -0500173static int vboot_asset_locate(const struct region_device *fw_main,
174 struct asset *asset)
Aaron Durbin899d13d2015-05-15 23:39:23 -0500175{
176 if (IS_ENABLED(CONFIG_MULTIPLE_CBFS_INSTANCES))
Aaron Durbinac12c66c2015-05-20 12:08:55 -0500177 return vboot_locate_by_multi_cbfs(fw_main, asset);
Aaron Durbin899d13d2015-05-15 23:39:23 -0500178 else
Aaron Durbinac12c66c2015-05-20 12:08:55 -0500179 return vboot_locate_by_components(fw_main, asset);
Aaron Durbin899d13d2015-05-15 23:39:23 -0500180}
181
Aaron Durbinac12c66c2015-05-20 12:08:55 -0500182/* This function is only called when vboot_active() returns 1. That
Aaron Durbin17200ad2015-05-01 16:48:54 -0500183 * means we are taking vboot paths. */
Aaron Durbinac12c66c2015-05-20 12:08:55 -0500184static int vboot_locate(struct asset *asset)
Aaron Durbin17200ad2015-05-01 16:48:54 -0500185{
Aaron Durbin4e50cdd2015-05-15 23:25:46 -0500186 struct region_device fw_main;
Aaron Durbin17200ad2015-05-01 16:48:54 -0500187
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 Durbinb5a20b22015-10-06 17:29:03 -0500194 if (vb2_get_selected_region(&fw_main))
Aaron Durbin4e50cdd2015-05-15 23:25:46 -0500195 die("failed to reference selected region\n");
Aaron Durbin17200ad2015-05-01 16:48:54 -0500196
Aaron Durbinac12c66c2015-05-20 12:08:55 -0500197 return vboot_asset_locate(&fw_main, asset);
Aaron Durbin17200ad2015-05-01 16:48:54 -0500198}
199
Aaron Durbinac12c66c2015-05-20 12:08:55 -0500200const struct asset_provider vboot_provider = {
Aaron Durbin17200ad2015-05-01 16:48:54 -0500201 .name = "VBOOT",
Aaron Durbinac12c66c2015-05-20 12:08:55 -0500202 .is_active = vboot_active,
Aaron Durbin899d13d2015-05-15 23:39:23 -0500203 .locate = vboot_locate,
Aaron Durbin17200ad2015-05-01 16:48:54 -0500204};