summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulius Werner <jwerner@chromium.org>2017-03-17 16:54:48 -0700
committerJulius Werner <jwerner@chromium.org>2017-03-28 22:17:35 +0200
commit73d042bd90bc8877f9bfd8b846578fe3e12444c3 (patch)
tree313a7814c4c9ca76e42b5239d07037e7ea537f42
parent5fc7c2896ae0d628903144041ff13349c79f2619 (diff)
downloadcoreboot-73d042bd90bc8877f9bfd8b846578fe3e12444c3.tar.gz
coreboot-73d042bd90bc8877f9bfd8b846578fe3e12444c3.tar.bz2
coreboot-73d042bd90bc8877f9bfd8b846578fe3e12444c3.zip
vboot: Disallow separate verstage after romstage, try to clarify logic
No board has ever tried to combine CONFIG_SEPARATE_VERSTAGE with CONFIG_VBOOT_STARTS_IN_ROMSTAGE. There are probably many reasons why this wouldn't work (e.g. x86 CAR migration logic currently always assumes verstage code to run pre-migration). It would also not really make sense: the reason we use separate verstages is to decrease bootblock size (mitigating the boot speed cost of slow boot ROM SPI drivers) and to allow the SRAM-saving RETURN_FROM_VERSTAGE trick, neither of which would apply to the after-romstage case. It is better to just forbid that case explicitly and give programmers more guarantees about what the verstage is (e.g. now the assumption that it runs pre-RAM is always valid). Since Kconfig dependencies aren't always guaranteed in the face of 'select' statements, also add some explicit compile-time assertions to the vboot code. We can simplify some of the loader logic which now no longer needs to provide for the forbidden case. In addition, also try to make some of the loader logic more readable by writing it in a more functional style that allows us to put more assertions about which cases should be unreachable in there, which will hopefully make it more robust and fail-fast with future changes (e.g. addition of new stages). Change-Id: Iaf60040af4eff711d9b80ee0e5950ce05958b3aa Signed-off-by: Julius Werner <jwerner@chromium.org> Reviewed-on: https://review.coreboot.org/18983 Reviewed-by: Aaron Durbin <adurbin@chromium.org> Tested-by: build bot (Jenkins)
-rw-r--r--src/include/memlayout.h5
-rw-r--r--src/vboot/Kconfig8
-rw-r--r--src/vboot/vboot_loader.c84
3 files changed, 50 insertions, 47 deletions
diff --git a/src/include/memlayout.h b/src/include/memlayout.h
index a68b21f4d694..b39a8955c954 100644
--- a/src/include/memlayout.h
+++ b/src/include/memlayout.h
@@ -153,7 +153,10 @@
STR(Verstage exceeded its allotted size! (sz))); \
INCLUDE "verstage/lib/program.ld"
- #define OVERLAP_VERSTAGE_ROMSTAGE(addr, size) VERSTAGE(addr, size)
+ #define OVERLAP_VERSTAGE_ROMSTAGE(addr, size) \
+ _ = ASSERT(IS_ENABLED(CONFIG_RETURN_FROM_VERSTAGE) == 1, \
+ "Must set RETURN_FROM_VERSTAGE to overlap romstage."); \
+ VERSTAGE(addr, size)
#else
#define VERSTAGE(addr, sz) \
REGION(verstage, addr, sz, 1)
diff --git a/src/vboot/Kconfig b/src/vboot/Kconfig
index 0c72d4775e8b..a92a2fa5e131 100644
--- a/src/vboot/Kconfig
+++ b/src/vboot/Kconfig
@@ -83,7 +83,13 @@ config VBOOT_DISABLE_DEV_ON_RECOVERY
config SEPARATE_VERSTAGE
bool "Vboot verification is built into a separate stage"
default n
- depends on VBOOT
+ depends on VBOOT && VBOOT_STARTS_IN_BOOTBLOCK
+ help
+ If this option is set, vboot verification runs in a standalone stage
+ that is loaded from the bootblock and exits into romstage. If it is
+ not set, the verification code is linked directly into the bootblock
+ or the romstage and runs as part of that stage (cf. related options
+ VBOOT_STARTS_IN_BOOTBLOCK/_ROMSTAGE and RETURN_FROM_VERSTAGE).
config RETURN_FROM_VERSTAGE
bool "The separate verification stage returns to its caller"
diff --git a/src/vboot/vboot_loader.c b/src/vboot/vboot_loader.c
index 9593358e3bdf..3629402f7e64 100644
--- a/src/vboot/vboot_loader.c
+++ b/src/vboot/vboot_loader.c
@@ -25,75 +25,69 @@
#include <vboot/symbols.h>
#include <vboot/vboot_common.h>
+/* Ensure vboot configuration is valid: */
+_Static_assert(IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK) +
+ IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE) == 1,
+ "vboot must either start in bootblock or romstage (not both!)");
+_Static_assert(!IS_ENABLED(CONFIG_SEPARATE_VERSTAGE) ||
+ IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK),
+ "stand-alone verstage must start in (i.e. after) bootblock");
+_Static_assert(!IS_ENABLED(CONFIG_RETURN_FROM_VERSTAGE) ||
+ IS_ENABLED(CONFIG_SEPARATE_VERSTAGE),
+ "return from verstage only makes sense for separate verstages");
+
/* The stage loading code is compiled and entered from multiple stages. The
* helper functions below attempt to provide more clarity on when certain
* code should be called. */
static int verification_should_run(void)
{
- if (ENV_VERSTAGE && IS_ENABLED(CONFIG_SEPARATE_VERSTAGE))
- return 1;
-
- if (!IS_ENABLED(CONFIG_SEPARATE_VERSTAGE)) {
- if (ENV_ROMSTAGE &&
- IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE))
- return 1;
- if (ENV_BOOTBLOCK &&
- IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK))
- return 1;
- }
-
- return 0;
+ if (IS_ENABLED(CONFIG_SEPARATE_VERSTAGE))
+ return ENV_VERSTAGE;
+ else if (IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE))
+ return ENV_ROMSTAGE;
+ else if (IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK))
+ return ENV_BOOTBLOCK;
+ else
+ die("impossible!");
}
static int verstage_should_load(void)
{
- if (!IS_ENABLED(CONFIG_SEPARATE_VERSTAGE))
+ if (IS_ENABLED(CONFIG_SEPARATE_VERSTAGE))
+ return ENV_BOOTBLOCK;
+ else
return 0;
-
- if (ENV_ROMSTAGE && IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE))
- return 1;
-
- if (ENV_BOOTBLOCK && IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK))
- return 1;
-
- return 0;
}
static int vboot_executed CAR_GLOBAL;
int vb2_logic_executed(void)
{
- /* If this stage is supposed to run the vboot logic ensure it has been
- * executed. */
- if (verification_should_run() && car_get_var(vboot_executed))
+ /* If we are in a stage that would load the verstage or execute the
+ vboot logic directly, we store the answer in a global. */
+ if (verstage_should_load() || verification_should_run())
+ return car_get_var(vboot_executed);
+
+ if (IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK)) {
+ /* All other stages are "after the bootblock" */
+ return !ENV_BOOTBLOCK;
+ } else if (IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE)) {
+ /* Post-RAM stages are "after the romstage" */
+#ifdef __PRE_RAM__
+ return 0;
+#else
return 1;
-
- /* If this stage is supposed to load verstage and verstage is returning
- * back to the calling stage check that it has been executed. */
- if (verstage_should_load() && IS_ENABLED(CONFIG_RETURN_FROM_VERSTAGE))
- if (car_get_var(vboot_executed))
- return 1;
-
- /* Handle all other stages post vboot execution. */
- if (!ENV_BOOTBLOCK) {
- if (IS_ENABLED(CONFIG_VBOOT_STARTS_IN_BOOTBLOCK))
- return 1;
- if (IS_ENABLED(CONFIG_VBOOT_STARTS_IN_ROMSTAGE) &&
- !ENV_ROMSTAGE)
- return 1;
+#endif
+ } else {
+ die("impossible!");
}
-
- return 0;
}
static void vboot_prepare(void)
{
if (verification_should_run()) {
- /*
- * Note that this path isn't taken when
- * CONFIG_RETURN_FROM_VERSTAGE is employed.
- */
+ /* Note: this path is not used for RETURN_FROM_VERSTAGE */
verstage_main();
car_set_var(vboot_executed, 1);
vb2_save_recovery_reason_vbnv();