From 0ad6f7fee9df31e1b35d4df9a8c373516416a235 Mon Sep 17 00:00:00 2001 From: Daisuke Nojiri Date: Fri, 19 Sep 2014 09:56:15 -0700 Subject: [PATCH] vboot2: load decompressed stage directly to load address this change allows vboot_load_stage to load a decompressed stage directly to the load address without using the cbfs cache. BUG=None TEST=Booted Nyan Blaze. BRANCH=None Signed-off-by: Daisuke Nojiri Change-Id: I76530276ff9a87b44f98a33f2c34bd5b2de6888f Reviewed-on: https://chromium-review.googlesource.com/219028 Reviewed-by: Aaron Durbin Commit-Queue: Daisuke Nojiri Tested-by: Daisuke Nojiri --- src/include/cbfs.h | 1 + src/lib/cbfs.c | 76 +++++++++++++---------- src/vendorcode/google/chromeos/chromeos.c | 31 +++------ 3 files changed, 53 insertions(+), 55 deletions(-) diff --git a/src/include/cbfs.h b/src/include/cbfs.h index c0098eacdb..4aaf7ec822 100644 --- a/src/include/cbfs.h +++ b/src/include/cbfs.h @@ -57,6 +57,7 @@ void *cbfs_load_optionrom(struct cbfs_media *media, uint16_t vendor, uint16_t device, void * dest); void *cbfs_load_payload(struct cbfs_media *media, const char *name); void *cbfs_load_stage(struct cbfs_media *media, const char *name); +void *cbfs_load_stage_by_offset(struct cbfs_media *media, ssize_t offset); /* Simple buffer for streaming media. */ struct cbfs_simple_buffer { diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c index 8cd8e084ae..20abeeba8b 100644 --- a/src/lib/cbfs.c +++ b/src/lib/cbfs.c @@ -169,10 +169,50 @@ void * cbfs_load_stage(struct cbfs_media *media, const char *name) #else +void *cbfs_load_stage_by_offset(struct cbfs_media *media, ssize_t offset) +{ + struct cbfs_stage stage; + + DEBUG("reading stage header: offset=0x%x len=%d type=%d offset=0x%x\n", + offset, file.len, file.type, file.offset); + if (cbfs_read(media, &stage, offset, sizeof(stage)) != sizeof(stage)) { + ERROR("ERROR: failed to read stage header\n"); + return (void *)-1; + } + + LOG("loading stage @ 0x%llx (%d bytes), entry @ 0x%llx\n", + stage.load, stage.memlen, stage.entry); + + /* Stages rely the below clearing so that the bss is initialized. */ + memset((void *)(uintptr_t)stage.load, 0, stage.memlen); + + if (stage.compression == CBFS_COMPRESS_NONE) { + if (cbfs_read(media, (void *)(uintptr_t)stage.load, + offset + sizeof(stage), stage.len) != stage.len) { + ERROR("ERROR: Reading stage failed.\n"); + return (void *)-1; + } + } else { + void *data = media->map(media, offset + sizeof(stage), + stage.len); + if (data == CBFS_MEDIA_INVALID_MAP_ADDRESS) { + ERROR("ERROR: Mapping stage failed.\n"); + return (void *)-1; + } + if (cbfs_decompress(stage.compression, data, + (void *)(uintptr_t)stage.load, stage.len)) + return (void *)-1; + media->unmap(media, data); + } + + DEBUG("stage loaded\n"); + + return (void *)(uintptr_t)stage.entry; +} + void *cbfs_load_stage(struct cbfs_media *media, const char *name) { struct cbfs_media default_media; - struct cbfs_stage stage; struct cbfs_file file; ssize_t offset; @@ -182,39 +222,7 @@ void *cbfs_load_stage(struct cbfs_media *media, const char *name) if (offset < 0 || file.type != CBFS_TYPE_STAGE) return (void *)-1; - DEBUG("reading stage header: offset=0x%x len=%d type=%d offset=0x%x\n", - offset, file.len, file.type, file.offset); - if (cbfs_read(media, &stage, offset, sizeof(stage)) != sizeof(stage)) - return (void *)-1; - - LOG("loading stage %s @ 0x%llx (%d bytes), entry @ 0x%llx\n", - name, - stage.load, stage.memlen, - stage.entry); - - /* Stages rely the below clearing so that the bss is initialized. */ - memset((void *)(uintptr_t)stage.load, 0, stage.memlen); - - if (stage.compression == CBFS_COMPRESS_NONE) { - if (cbfs_read(media, (void *)(uintptr_t)stage.load, - offset + sizeof(stage), stage.len) != stage.len) - return (void *)-1; - } else { - void *data = media->map(media, offset + sizeof(stage), - stage.len); - if (data == CBFS_MEDIA_INVALID_MAP_ADDRESS) { - ERROR("ERROR: Mapping %s failed.\n", name); - return (void *)-1; - } - if (cbfs_decompress(stage.compression, data, - (void *)(uintptr_t)stage.load, stage.len)) - return (void *)-1; - media->unmap(media, data); - } - - DEBUG("stage %s loaded\n", name); - - return (void *)(uintptr_t)stage.entry; + return cbfs_load_stage_by_offset(media, offset); } #endif /* CONFIG_RELOCATABLE_RAMSTAGE */ diff --git a/src/vendorcode/google/chromeos/chromeos.c b/src/vendorcode/google/chromeos/chromeos.c index bd72e77e6c..5696aec787 100644 --- a/src/vendorcode/google/chromeos/chromeos.c +++ b/src/vendorcode/google/chromeos/chromeos.c @@ -222,9 +222,10 @@ void *vboot_load_stage(int stage_index, struct vboot_region *fw_main, struct vboot_components *fw_info) { - struct cbfs_stage *stage; + struct cbfs_media default_media, *media = &default_media; uintptr_t fc_addr; uint32_t fc_size; + void *entry; if (stage_index >= fw_info->num_components) { printk(BIOS_INFO, "invalid stage index\n"); @@ -239,27 +240,15 @@ void *vboot_load_stage(int stage_index, return NULL; } - /* Loading to cbfs cache. This stage data must be retained until it's - * decompressed. */ - stage = vboot_get_region(fc_addr, fc_size, NULL); + init_default_cbfs_media(media); - if (stage == NULL) { - printk(BIOS_INFO, "failed to load a stage\n"); - return NULL; - } - - /* Stages rely the below clearing so that the bss is initialized. */ - memset((void *) (uintptr_t)stage->load, 0, stage->memlen); - - if (cbfs_decompress(stage->compression, - (unsigned char *)stage + sizeof(*stage), - (void *) (uintptr_t) stage->load, - stage->len)) { - printk(BIOS_INFO, "failed to decompress a stage\n"); - return NULL; - } - - return (void *)(uintptr_t)stage->entry; + /* we're making cbfs access offset outside of the region managed by + * cbfs. this works because cbfs_load_stage_by_offset does not check + * the offset. */ + entry = cbfs_load_stage_by_offset(media, fc_addr); + if (entry == (void *)-1) + entry = NULL; + return entry; } struct vb2_working_data * const vboot_get_working_data(void)