From 00e9127e2df4f5597ae05896866c8c8e373f6178 Mon Sep 17 00:00:00 2001 From: Aaron Durbin Date: Wed, 23 Jul 2014 15:32:26 -0500 Subject: [PATCH] vboot: split loading and running of ramstage The vboot module previously assumed the CPU running the verfication would also be the one executing the next stage of execution. That isn't true for all platforms. Therefore, provide the ability to load and return the entry point by way of vboot_verify_firmware_get_entry(). vboot_verify_firmware() still does the same thing as it previously did -- load and run from the current execution context. BUG=chrome-os-partner:30784 BRANCH=None TEST=Built for nyan. Change-Id: Id06c3d382edfe84adb170e7f52c12be58b88bab9 Signed-off-by: Aaron Durbin Reviewed-on: https://chromium-review.googlesource.com/209592 Reviewed-by: Furquan Shaikh Tested-by: Furquan Shaikh --- src/vendorcode/google/chromeos/chromeos.h | 10 ++++ src/vendorcode/google/chromeos/vboot_loader.c | 52 +++++++++++-------- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/src/vendorcode/google/chromeos/chromeos.h b/src/vendorcode/google/chromeos/chromeos.h index 2235639d78..7ca187d96d 100644 --- a/src/vendorcode/google/chromeos/chromeos.h +++ b/src/vendorcode/google/chromeos/chromeos.h @@ -71,11 +71,21 @@ struct romstage_handoff; * returned on error else the location of the requested region. */ void *vboot_get_region(uintptr_t offset_addr, size_t size, void *dest); +/* + * vboot_verify_firmware_get_entry() returns NULL if verification failed or + * the address to the next stage of firmware to run. + */ +void *vboot_verify_firmware_get_entry(struct romstage_handoff *handoff); void vboot_verify_firmware(struct romstage_handoff *handoff); void *vboot_get_payload(int *len); /* Returns 0 on success < 0 on error. */ int vboot_get_handoff_info(void **addr, uint32_t *size); #else +static inline void * +vboot_verify_firmware_get_entry(struct romstage_handoff *handoff) +{ + return NULL; +} static inline void vboot_verify_firmware(struct romstage_handoff *h) {} static inline void *vboot_get_payload(int *len) { return NULL; } static inline int vboot_get_handoff_info(void **addr, uint32_t *size) diff --git a/src/vendorcode/google/chromeos/vboot_loader.c b/src/vendorcode/google/chromeos/vboot_loader.c index 007380f21f..91c391d0bf 100644 --- a/src/vendorcode/google/chromeos/vboot_loader.c +++ b/src/vendorcode/google/chromeos/vboot_loader.c @@ -314,8 +314,8 @@ static void vboot_invoke_wrapper(struct vboot_handoff *vboot_handoff) } #if CONFIG_RELOCATABLE_RAMSTAGE -static void vboot_load_ramstage(struct vboot_handoff *vboot_handoff, - struct romstage_handoff *handoff) +static void *vboot_load_ramstage(struct vboot_handoff *vboot_handoff, + struct romstage_handoff *handoff) { struct cbfs_stage *stage; const struct firmware_component *fwc; @@ -327,14 +327,14 @@ static void vboot_load_ramstage(struct vboot_handoff *vboot_handoff, if (CONFIG_VBOOT_RAMSTAGE_INDEX >= MAX_PARSED_FW_COMPONENTS) { printk(BIOS_ERR, "Invalid ramstage index: %d\n", CONFIG_VBOOT_RAMSTAGE_INDEX); - return; + return NULL; } /* Check for invalid address. */ fwc = &vboot_handoff->components[CONFIG_VBOOT_RAMSTAGE_INDEX]; if (fwc->address == 0) { printk(BIOS_DEBUG, "RW ramstage image address invalid.\n"); - return; + return NULL; } printk(BIOS_DEBUG, "RW ramstage image at 0x%08x, 0x%08x bytes.\n", @@ -347,33 +347,34 @@ static void vboot_load_ramstage(struct vboot_handoff *vboot_handoff, if (rmodule_stage_load(&rmod_load, stage)) { vboot_handoff->selected_firmware = VB_SELECT_FIRMWARE_READONLY; printk(BIOS_DEBUG, "Could not load ramstage region.\n"); - return; + return NULL; } cache_loaded_ramstage(handoff, rmod_load.cbmem_entry, rmod_load.entry); timestamp_add_now(TS_END_COPYRAM); - stage_exit(rmod_load.entry); + return rmod_load.entry; } #else /* CONFIG_RELOCATABLE_RAMSTAGE */ -static void vboot_load_ramstage(struct vboot_handoff *vboot_handoff, - struct romstage_handoff *handoff) +static void *vboot_load_ramstage(struct vboot_handoff *vboot_handoff, + struct romstage_handoff *handoff) { struct cbfs_stage *stage; const struct firmware_component *fwc; + void *entry; if (CONFIG_VBOOT_RAMSTAGE_INDEX >= MAX_PARSED_FW_COMPONENTS) { printk(BIOS_ERR, "Invalid ramstage index: %d\n", CONFIG_VBOOT_RAMSTAGE_INDEX); - return; + return NULL; } /* Check for invalid address. */ fwc = &vboot_handoff->components[CONFIG_VBOOT_RAMSTAGE_INDEX]; if (fwc->address == 0) { printk(BIOS_DEBUG, "RW ramstage image address invalid.\n"); - return; + return NULL; } printk(BIOS_DEBUG, "RW ramstage image at 0x%08x, 0x%08x bytes.\n", @@ -384,34 +385,35 @@ static void vboot_load_ramstage(struct vboot_handoff *vboot_handoff, if (stage == NULL) { printk(BIOS_DEBUG, "Unable to get RW ramstage region.\n"); - return; + return NULL; } timestamp_add_now(TS_START_COPYRAM); /* Stages rely the below clearing so that the bss is initialized. */ - memset((void *) (uintptr_t) stage->load, 0, stage->memlen); + entry = (void *)(uintptr_t)stage->load; + memset(entry, 0, stage->memlen); if (cbfs_decompress(stage->compression, ((unsigned char *) stage) + sizeof(struct cbfs_stage), - (void *) (uintptr_t) stage->load, - stage->len)) - return; + entry, stage->len)) + return NULL; timestamp_add_now(TS_END_COPYRAM); - stage_exit((void *)(uintptr_t)stage->entry); + return entry; } #endif /* CONFIG_RELOCATABLE_RAMSTAGE */ -void vboot_verify_firmware(struct romstage_handoff *handoff) + +void *vboot_verify_firmware_get_entry(struct romstage_handoff *handoff) { struct vboot_handoff *vboot_handoff; /* Don't go down verified boot path on S3 resume. */ if (handoff != NULL && handoff->s3_resume) - return; + return NULL; timestamp_add_now(TS_START_VBOOT); @@ -420,7 +422,7 @@ void vboot_verify_firmware(struct romstage_handoff *handoff) if (vboot_handoff == NULL) { printk(BIOS_DEBUG, "Could not add vboot_handoff structure.\n"); - return; + return NULL; } memset(vboot_handoff, 0, sizeof(*vboot_handoff)); @@ -434,9 +436,17 @@ void vboot_verify_firmware(struct romstage_handoff *handoff) vboot_handoff->selected_firmware != VB_SELECT_FIRMWARE_B) { printk(BIOS_DEBUG, "No RW firmware selected: 0x%08x\n", vboot_handoff->selected_firmware); - return; + return NULL; } /* Load ramstage from the vboot_handoff structure. */ - vboot_load_ramstage(vboot_handoff, handoff); + return vboot_load_ramstage(vboot_handoff, handoff); +} + +void vboot_verify_firmware(struct romstage_handoff *handoff) +{ + void *entry = vboot_verify_firmware_get_entry(handoff); + + if (entry != NULL) + stage_exit(entry); }