From b593366e349673cd4ef5b933849f78e6e958d626 Mon Sep 17 00:00:00 2001 From: Aaron Durbin Date: Wed, 7 Oct 2015 16:03:41 -0500 Subject: [PATCH] vboot: prepare for x86 verstage In order to support x86 verstage proper the work buffer needs to live in cache-as-ram. However, after cache-as-ram is torn down one still needs the verification results to know which slot was selected. Though the platforms with a dedicated SRAM can just use the work buffer in SRAM, the x86 cache-as-ram platforms need a place to stash the results. For that situation cbmem is employed. This works because when cbmem is initialized cache-as-ram is still enabled. The VBOOT_DYNAMIC_WORK_BUFFER case assumes verified boot doesn't start until after cbmem is up. That doesn't change, but it's a goal to get rid of that option entirely once all other x86 platforms are moved over to pre-romstage vboot. BUG=chrome-os-partner:44827 BRANCH=None TEST=Built and booted glados with pre-romstage verification as well as VBOOT_DYNAMIC_WORK_BUFFER case. Change-Id: I7eacd0edb2b6ca52b59b74075d17c00b50676d4c Signed-off-by: Aaron Durbin Reviewed-on: http://review.coreboot.org/11821 Tested-by: build bot (Jenkins) Reviewed-by: Patrick Georgi --- src/commonlib/include/commonlib/cbmem_id.h | 2 + .../google/chromeos/vboot2/common.c | 81 ++++++++++++++++--- src/vendorcode/google/chromeos/vboot2/misc.h | 3 + .../google/chromeos/vboot2/vboot_handoff.c | 14 ++++ .../google/chromeos/vboot2/vboot_loader.c | 14 +++- 5 files changed, 99 insertions(+), 15 deletions(-) diff --git a/src/commonlib/include/commonlib/cbmem_id.h b/src/commonlib/include/commonlib/cbmem_id.h index 6812c41cc1..4a5b66082b 100644 --- a/src/commonlib/include/commonlib/cbmem_id.h +++ b/src/commonlib/include/commonlib/cbmem_id.h @@ -65,6 +65,7 @@ #define CBMEM_ID_TCPA_LOG 0x54435041 #define CBMEM_ID_TIMESTAMP 0x54494d45 #define CBMEM_ID_VBOOT_HANDOFF 0x780074f0 +#define CBMEM_ID_VBOOT_SEL_REG 0x780074f1 #define CBMEM_ID_VBOOT_WORKBUF 0x78007343 #define CBMEM_ID_WIFI_CALIBRATION 0x57494649 @@ -108,6 +109,7 @@ { CBMEM_ID_TCPA_LOG, "TCPA LOG " }, \ { CBMEM_ID_TIMESTAMP, "TIME STAMP " }, \ { CBMEM_ID_VBOOT_HANDOFF, "VBOOT " }, \ + { CBMEM_ID_VBOOT_SEL_REG, "VBOOT SEL " }, \ { CBMEM_ID_VBOOT_WORKBUF, "VBOOT WORK " }, \ { CBMEM_ID_WIFI_CALIBRATION, "WIFI CLBR " }, #endif /* _CBMEM_ID_H_ */ diff --git a/src/vendorcode/google/chromeos/vboot2/common.c b/src/vendorcode/google/chromeos/vboot2/common.c index a33fb8e98e..663ffd892b 100644 --- a/src/vendorcode/google/chromeos/vboot2/common.c +++ b/src/vendorcode/google/chromeos/vboot2/common.c @@ -28,6 +28,11 @@ #include "../vboot_handoff.h" #include "misc.h" +struct selected_region { + uint32_t offset; + uint32_t size; +}; + /* * this is placed at the start of the vboot work buffer. selected_region is used * for the verstage to return the location of the selected slot. buffer is used @@ -35,8 +40,7 @@ * stage boundaries. */ struct vb2_working_data { - uint32_t selected_region_offset; - uint32_t selected_region_size; + struct selected_region selected_region; /* offset of the buffer from the start of this struct */ uint32_t buffer_offset; uint32_t buffer_size; @@ -61,6 +65,30 @@ static size_t vb2_working_data_size(void) return _vboot2_work_size; } +static struct selected_region *vb2_selected_region(void) +{ + struct selected_region *sel_reg = NULL; + + /* Ramstage always uses cbmem as a source of truth. */ + if (ENV_RAMSTAGE) + sel_reg = cbmem_find(CBMEM_ID_VBOOT_SEL_REG); + else if (ENV_ROMSTAGE) { + /* Try cbmem first. Fall back on working data if not found. */ + sel_reg = cbmem_find(CBMEM_ID_VBOOT_SEL_REG); + + if (sel_reg == NULL) { + struct vb2_working_data *wd = vboot_get_working_data(); + sel_reg = &wd->selected_region; + } + } else { + /* Stages such as bootblock and verstage use working data. */ + struct vb2_working_data *wd = vboot_get_working_data(); + sel_reg = &wd->selected_region; + } + + return sel_reg; +} + void vb2_init_work_context(struct vb2_context *ctx) { struct vb2_working_data *wd; @@ -93,28 +121,57 @@ struct vb2_shared_data *vb2_get_shared_data(void) int vb2_get_selected_region(struct region_device *rdev) { - const struct vb2_working_data *wd = vboot_get_working_data(); - struct region reg = { - .offset = wd->selected_region_offset, - .size = wd->selected_region_size, + const struct selected_region *reg = vb2_selected_region(); + struct region region = { + .offset = reg->offset, + .size = reg->size, }; - return vboot_region_device(®, rdev); + return vboot_region_device(®ion, rdev); } void vb2_set_selected_region(struct region_device *rdev) { - struct vb2_working_data *wd = vboot_get_working_data(); - wd->selected_region_offset = region_device_offset(rdev); - wd->selected_region_size = region_device_sz(rdev); + struct selected_region *reg = vb2_selected_region(); + reg->offset = region_device_offset(rdev); + reg->size = region_device_sz(rdev); } int vboot_is_slot_selected(void) { - const struct vb2_working_data *wd = vboot_get_working_data(); - return wd->selected_region_size > 0; + const struct selected_region *reg = vb2_selected_region(); + return reg->size > 0; } int vboot_is_readonly_path(void) { return !vboot_is_slot_selected(); } + +void vb2_store_selected_region(void) +{ + const struct vb2_working_data *wd; + struct selected_region *sel_reg; + + /* Always use the working data in this path since it's the object + * which has the result.. */ + wd = vboot_get_working_data(); + + sel_reg = cbmem_add(CBMEM_ID_VBOOT_SEL_REG, sizeof(*sel_reg)); + + sel_reg->offset = wd->selected_region.offset; + sel_reg->size = wd->selected_region.size; +} + +/* + * For platforms that employ VBOOT_DYNAMIC_WORK_BUFFER, the vboot + * verification doesn't happen until after cbmem is brought online. + * Therefore, the selected region contents would not be initialized + * so don't automatically add results when cbmem comes online. + */ +#if !IS_ENABLED(CONFIG_VBOOT_DYNAMIC_WORK_BUFFER) +static void vb2_store_selected_region_cbmem(int unused) +{ + vb2_store_selected_region(); +} +ROMSTAGE_CBMEM_INIT_HOOK(vb2_store_selected_region_cbmem) +#endif diff --git a/src/vendorcode/google/chromeos/vboot2/misc.h b/src/vendorcode/google/chromeos/vboot2/misc.h index fbbc46ef5c..2c26461ad4 100644 --- a/src/vendorcode/google/chromeos/vboot2/misc.h +++ b/src/vendorcode/google/chromeos/vboot2/misc.h @@ -39,4 +39,7 @@ void vb2_set_selected_region(struct region_device *rdev); int vboot_is_slot_selected(void); int vboot_is_readonly_path(void); +/* Store the selected region in cbmem for later use. */ +void vb2_store_selected_region(void); + #endif /* __CHROMEOS_VBOOT2_MISC_H__ */ diff --git a/src/vendorcode/google/chromeos/vboot2/vboot_handoff.c b/src/vendorcode/google/chromeos/vboot2/vboot_handoff.c index bf7d6542eb..769e2679ef 100644 --- a/src/vendorcode/google/chromeos/vboot2/vboot_handoff.c +++ b/src/vendorcode/google/chromeos/vboot2/vboot_handoff.c @@ -171,3 +171,17 @@ void vboot_fill_handoff(void) rdev_munmap(&fw_main, fw_info); } + +/* + * For platforms that employ VBOOT_DYNAMIC_WORK_BUFFER, the vboot + * verification doesn't happen until after cbmem is brought online. + * Therefore, the vboot results would not be initialized so don't + * automatically add results when cbmem comes online. + */ +#if !IS_ENABLED(CONFIG_VBOOT_DYNAMIC_WORK_BUFFER) +static void vb2_fill_handoff_cbmem(int unused) +{ + vboot_fill_handoff(); +} +ROMSTAGE_CBMEM_INIT_HOOK(vb2_fill_handoff_cbmem) +#endif diff --git a/src/vendorcode/google/chromeos/vboot2/vboot_loader.c b/src/vendorcode/google/chromeos/vboot2/vboot_loader.c index bb7bc4c828..d2e77586e8 100644 --- a/src/vendorcode/google/chromeos/vboot2/vboot_loader.c +++ b/src/vendorcode/google/chromeos/vboot2/vboot_loader.c @@ -98,10 +98,18 @@ static int vboot_active(struct asset *asset) return 0; } - /* Fill in vboot handoff structure before moving to ramstage so all - * downstream users have access to vboot results. */ - if (ENV_ROMSTAGE) + /* + * Fill in vboot cbmem objects before moving to ramstage so all + * downstream users have access to vboot results. This path only + * applies to platforms employing VBOOT_DYNAMIC_WORK_BUFFER because + * cbmem comes online prior to vboot verification taking place. For + * other platforms the vboot cbmem objects are initialized when + * cbmem comes online. + */ + if (ENV_ROMSTAGE && IS_ENABLED(CONFIG_VBOOT_DYNAMIC_WORK_BUFFER)) { + vb2_store_selected_region(); vboot_fill_handoff(); + } return vboot_is_slot_selected(); }