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. |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 14 | */ |
| 15 | |
Aaron Durbin | 6d720f3 | 2015-12-08 17:00:23 -0600 | [diff] [blame] | 16 | #include <arch/early_variables.h> |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 17 | #include <cbfs.h> |
| 18 | #include <console/console.h> |
Aaron Durbin | f7ce40b | 2016-08-24 14:58:12 -0500 | [diff] [blame] | 19 | #include <ec/google/chromeec/ec.h> |
Aaron Durbin | 09560fa | 2015-05-12 16:43:10 -0500 | [diff] [blame] | 20 | #include <rmodule.h> |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 21 | #include <string.h> |
Philipp Deppenwiese | fea2429 | 2017-10-17 17:02:29 +0200 | [diff] [blame] | 22 | #include <security/vboot/misc.h> |
| 23 | #include <security/vboot/symbols.h> |
| 24 | #include <security/vboot/vboot_common.h> |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 25 | |
Julius Werner | 73d042b | 2017-03-17 16:54:48 -0700 | [diff] [blame] | 26 | /* Ensure vboot configuration is valid: */ |
| 27 | _Static_assert(IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK) + |
| 28 | IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE) == 1, |
| 29 | "vboot must either start in bootblock or romstage (not both!)"); |
Julius Werner | 58c3938 | 2017-02-13 17:53:29 -0800 | [diff] [blame] | 30 | _Static_assert(!IS_ENABLED(CONFIG_VBOOT_SEPARATE_VERSTAGE) || |
Julius Werner | 73d042b | 2017-03-17 16:54:48 -0700 | [diff] [blame] | 31 | IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK), |
| 32 | "stand-alone verstage must start in (i.e. after) bootblock"); |
Julius Werner | 58c3938 | 2017-02-13 17:53:29 -0800 | [diff] [blame] | 33 | _Static_assert(!IS_ENABLED(CONFIG_VBOOT_RETURN_FROM_VERSTAGE) || |
| 34 | IS_ENABLED(CONFIG_VBOOT_SEPARATE_VERSTAGE), |
Julius Werner | 73d042b | 2017-03-17 16:54:48 -0700 | [diff] [blame] | 35 | "return from verstage only makes sense for separate verstages"); |
| 36 | |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 37 | /* The stage loading code is compiled and entered from multiple stages. The |
| 38 | * helper functions below attempt to provide more clarity on when certain |
| 39 | * code should be called. */ |
| 40 | |
| 41 | static int verification_should_run(void) |
| 42 | { |
Julius Werner | 58c3938 | 2017-02-13 17:53:29 -0800 | [diff] [blame] | 43 | if (IS_ENABLED(CONFIG_VBOOT_SEPARATE_VERSTAGE)) |
Julius Werner | 73d042b | 2017-03-17 16:54:48 -0700 | [diff] [blame] | 44 | return ENV_VERSTAGE; |
| 45 | else if (IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE)) |
| 46 | return ENV_ROMSTAGE; |
| 47 | else if (IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK)) |
| 48 | return ENV_BOOTBLOCK; |
| 49 | else |
| 50 | die("impossible!"); |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 51 | } |
| 52 | |
| 53 | static int verstage_should_load(void) |
| 54 | { |
Julius Werner | 58c3938 | 2017-02-13 17:53:29 -0800 | [diff] [blame] | 55 | if (IS_ENABLED(CONFIG_VBOOT_SEPARATE_VERSTAGE)) |
Julius Werner | 73d042b | 2017-03-17 16:54:48 -0700 | [diff] [blame] | 56 | return ENV_BOOTBLOCK; |
| 57 | else |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 58 | return 0; |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 59 | } |
| 60 | |
Aaron Durbin | 6d720f3 | 2015-12-08 17:00:23 -0600 | [diff] [blame] | 61 | static int vboot_executed CAR_GLOBAL; |
| 62 | |
Furquan Shaikh | a6c5ddd | 2016-07-22 06:59:40 -0700 | [diff] [blame] | 63 | int vb2_logic_executed(void) |
Aaron Durbin | 6d720f3 | 2015-12-08 17:00:23 -0600 | [diff] [blame] | 64 | { |
Julius Werner | 73d042b | 2017-03-17 16:54:48 -0700 | [diff] [blame] | 65 | /* If we are in a stage that would load the verstage or execute the |
| 66 | vboot logic directly, we store the answer in a global. */ |
| 67 | if (verstage_should_load() || verification_should_run()) |
| 68 | return car_get_var(vboot_executed); |
| 69 | |
| 70 | if (IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK)) { |
| 71 | /* All other stages are "after the bootblock" */ |
| 72 | return !ENV_BOOTBLOCK; |
| 73 | } else if (IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE)) { |
| 74 | /* Post-RAM stages are "after the romstage" */ |
| 75 | #ifdef __PRE_RAM__ |
| 76 | return 0; |
| 77 | #else |
Aaron Durbin | 6d720f3 | 2015-12-08 17:00:23 -0600 | [diff] [blame] | 78 | return 1; |
Julius Werner | 73d042b | 2017-03-17 16:54:48 -0700 | [diff] [blame] | 79 | #endif |
| 80 | } else { |
| 81 | die("impossible!"); |
Aaron Durbin | 6d720f3 | 2015-12-08 17:00:23 -0600 | [diff] [blame] | 82 | } |
Aaron Durbin | 6d720f3 | 2015-12-08 17:00:23 -0600 | [diff] [blame] | 83 | } |
| 84 | |
| 85 | static void vboot_prepare(void) |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 86 | { |
Paul Kocialkowski | 1811768 | 2016-05-14 15:30:52 +0200 | [diff] [blame] | 87 | if (verification_should_run()) { |
Julius Werner | 58c3938 | 2017-02-13 17:53:29 -0800 | [diff] [blame] | 88 | /* Note: this path is not used for VBOOT_RETURN_FROM_VERSTAGE */ |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 89 | verstage_main(); |
Aaron Durbin | 6d720f3 | 2015-12-08 17:00:23 -0600 | [diff] [blame] | 90 | car_set_var(vboot_executed, 1); |
Furquan Shaikh | 85aa135 | 2016-07-22 08:56:43 -0700 | [diff] [blame] | 91 | vb2_save_recovery_reason_vbnv(); |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 92 | } else if (verstage_should_load()) { |
Aaron Durbin | 37a5d15 | 2015-09-17 16:09:30 -0500 | [diff] [blame] | 93 | struct cbfsf file; |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 94 | struct prog verstage = |
Aaron Durbin | 7e7a4df | 2015-12-08 14:34:35 -0600 | [diff] [blame] | 95 | PROG_INIT(PROG_VERSTAGE, |
Aaron Durbin | ac12c66c | 2015-05-20 12:08:55 -0500 | [diff] [blame] | 96 | CONFIG_CBFS_PREFIX "/verstage"); |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 97 | |
Aaron Durbin | ce2c50d | 2015-05-13 13:33:27 -0500 | [diff] [blame] | 98 | printk(BIOS_DEBUG, "VBOOT: Loading verstage.\n"); |
| 99 | |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 100 | /* load verstage from RO */ |
Aaron Durbin | 37a5d15 | 2015-09-17 16:09:30 -0500 | [diff] [blame] | 101 | if (cbfs_boot_locate(&file, prog_name(&verstage), NULL)) |
| 102 | die("failed to load verstage"); |
| 103 | |
| 104 | cbfs_file_data(prog_rdev(&verstage), &file); |
| 105 | |
| 106 | if (cbfs_prog_stage_load(&verstage)) |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 107 | die("failed to load verstage"); |
| 108 | |
| 109 | /* verify and select a slot */ |
| 110 | prog_run(&verstage); |
| 111 | |
| 112 | /* This is not actually possible to hit this condition at |
| 113 | * runtime, but this provides a hint to the compiler for dead |
| 114 | * code elimination below. */ |
Julius Werner | 58c3938 | 2017-02-13 17:53:29 -0800 | [diff] [blame] | 115 | if (!IS_ENABLED(CONFIG_VBOOT_RETURN_FROM_VERSTAGE)) |
Aaron Durbin | 6d720f3 | 2015-12-08 17:00:23 -0600 | [diff] [blame] | 116 | return; |
| 117 | |
| 118 | car_set_var(vboot_executed, 1); |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 119 | } |
| 120 | |
Aaron Durbin | b593366 | 2015-10-07 16:03:41 -0500 | [diff] [blame] | 121 | /* |
| 122 | * Fill in vboot cbmem objects before moving to ramstage so all |
| 123 | * downstream users have access to vboot results. This path only |
Julius Werner | fa8fa7d | 2017-03-16 19:32:48 -0700 | [diff] [blame] | 124 | * applies to platforms employing VBOOT_STARTS_IN_ROMSTAGE because |
Aaron Durbin | b593366 | 2015-10-07 16:03:41 -0500 | [diff] [blame] | 125 | * cbmem comes online prior to vboot verification taking place. For |
| 126 | * other platforms the vboot cbmem objects are initialized when |
| 127 | * cbmem comes online. |
| 128 | */ |
Julius Werner | fa8fa7d | 2017-03-16 19:32:48 -0700 | [diff] [blame] | 129 | if (ENV_ROMSTAGE && IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE)) { |
Aaron Durbin | b593366 | 2015-10-07 16:03:41 -0500 | [diff] [blame] | 130 | vb2_store_selected_region(); |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 131 | vboot_fill_handoff(); |
Aaron Durbin | b593366 | 2015-10-07 16:03:41 -0500 | [diff] [blame] | 132 | } |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 133 | } |
| 134 | |
Aaron Durbin | 6d720f3 | 2015-12-08 17:00:23 -0600 | [diff] [blame] | 135 | static int vboot_locate(struct cbfs_props *props) |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 136 | { |
Aaron Durbin | 6d720f3 | 2015-12-08 17:00:23 -0600 | [diff] [blame] | 137 | struct region selected_region; |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 138 | |
Aaron Durbin | 6d720f3 | 2015-12-08 17:00:23 -0600 | [diff] [blame] | 139 | /* Don't honor vboot results until the vboot logic has run. */ |
Furquan Shaikh | a6c5ddd | 2016-07-22 06:59:40 -0700 | [diff] [blame] | 140 | if (!vb2_logic_executed()) |
Aaron Durbin | b6981c0 | 2015-05-15 15:57:51 -0500 | [diff] [blame] | 141 | return -1; |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 142 | |
Aaron Durbin | 6d720f3 | 2015-12-08 17:00:23 -0600 | [diff] [blame] | 143 | if (vb2_get_selected_region(&selected_region)) |
Aaron Durbin | 4e50cdd | 2015-05-15 23:25:46 -0500 | [diff] [blame] | 144 | return -1; |
Aaron Durbin | b6981c0 | 2015-05-15 15:57:51 -0500 | [diff] [blame] | 145 | |
Aaron Durbin | 6d720f3 | 2015-12-08 17:00:23 -0600 | [diff] [blame] | 146 | props->offset = region_offset(&selected_region); |
| 147 | props->size = region_sz(&selected_region); |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 148 | |
Aaron Durbin | b6981c0 | 2015-05-15 15:57:51 -0500 | [diff] [blame] | 149 | return 0; |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 150 | } |
| 151 | |
Aaron Durbin | 6d720f3 | 2015-12-08 17:00:23 -0600 | [diff] [blame] | 152 | const struct cbfs_locator vboot_locator = { |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 153 | .name = "VBOOT", |
Aaron Durbin | 6d720f3 | 2015-12-08 17:00:23 -0600 | [diff] [blame] | 154 | .prepare = vboot_prepare, |
Aaron Durbin | 899d13d | 2015-05-15 23:39:23 -0500 | [diff] [blame] | 155 | .locate = vboot_locate, |
Aaron Durbin | 17200ad | 2015-05-01 16:48:54 -0500 | [diff] [blame] | 156 | }; |