From d04639b3d62dbd6a5fc7f48493411b9e74f990d1 Mon Sep 17 00:00:00 2001 From: Aaron Durbin Date: Sun, 17 Jul 2016 23:23:59 -0500 Subject: drivers/intel/fsp2_0: handle XIP and non-XIP for FSPM component The previously implementation for loading the FSPM component didn't handle platforms which expects FSPM to be XIP. For the non-XIP case, romstage's address space wasn't fully being checked for overlaps. Lastly, fixup the API as the range_entry isn't needed any longer. This API change requires a apollolake to be updated as well. BUG=chrome-os-partner:52679 Change-Id: I24d0c7d123d12f15a8477e1025bf0901e2d702e7 Signed-off-by: Aaron Durbin Reviewed-on: https://review.coreboot.org/15741 Tested-by: build bot (Jenkins) Reviewed-by: Furquan Shaikh --- src/drivers/intel/fsp2_0/include/fsp/api.h | 5 +- src/drivers/intel/fsp2_0/memory_init.c | 88 +++++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 5 deletions(-) (limited to 'src/drivers/intel/fsp2_0') diff --git a/src/drivers/intel/fsp2_0/include/fsp/api.h b/src/drivers/intel/fsp2_0/include/fsp/api.h index 9f8aae7f80..510163d77d 100644 --- a/src/drivers/intel/fsp2_0/include/fsp/api.h +++ b/src/drivers/intel/fsp2_0/include/fsp/api.h @@ -58,7 +58,7 @@ enum fsp_notify_phase { /* Main FSP stages */ -enum fsp_status fsp_memory_init(struct range_entry *r, bool s3wake); +enum fsp_status fsp_memory_init(bool s3wake); enum fsp_status fsp_silicon_init(struct range_entry *r); enum fsp_status fsp_notify(enum fsp_notify_phase phase); @@ -74,14 +74,13 @@ void platform_fsp_silicon_init_params_cb(struct FSPS_UPD *supd); * points and map 1:1 to the FSP entry points of the same name. * * ### fsp_memory_init(): - * - r: memory range that the binary is allowed to be loaded into * - s3wake: boolean indicating if the system is waking from resume * * This function is responsible for loading and executing the memory * initialization code from the FSP-M binary. It expects this binary to reside * in cbfs as FSP_M_FILE. * - * The function takes two parameters, which are described above, but does not + * The function takes one parameter, which is described above, but does not * take in memory parameters as an argument. The memory parameters can be filled * in with platform_fsp_memory_init_params_cb(). This is a callback symbol * that fsp_memory_init() will call. The platform must provide this symbol. diff --git a/src/drivers/intel/fsp2_0/memory_init.c b/src/drivers/intel/fsp2_0/memory_init.c index 700d40fa7f..497a5dee47 100644 --- a/src/drivers/intel/fsp2_0/memory_init.c +++ b/src/drivers/intel/fsp2_0/memory_init.c @@ -14,15 +14,18 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include #include +#include #include typedef asmlinkage enum fsp_status (*fsp_memory_init_fn) @@ -153,12 +156,93 @@ static enum fsp_status do_fsp_memory_init(struct fsp_header *hdr, bool s3wake) return do_fsp_post_memory_init(hob_list_ptr, s3wake); } -enum fsp_status fsp_memory_init(struct range_entry *range, bool s3wake) +/* Load the binary into the memory specified by the info header. */ +static enum cb_err load_fspm_mem(struct fsp_header *hdr, + const struct region_device *rdev) +{ + struct memranges ranges; + struct range_entry freeranges[2]; + const struct range_entry *r; + uintptr_t fspm_begin; + uintptr_t fspm_end; + + if (fsp_validate_component(hdr, rdev) != CB_SUCCESS) + return CB_ERR; + + fspm_begin = hdr->image_base; + fspm_end = fspm_begin + hdr->image_size; + + /* Build up memory map of romstage address space including CAR. */ + memranges_init_empty(&ranges, &freeranges[0], ARRAY_SIZE(freeranges)); + memranges_insert(&ranges, (uintptr_t)_car_region_start, + _car_relocatable_data_end - _car_region_start, 0); + memranges_insert(&ranges, (uintptr_t)_program, _program_size, 0); + memranges_each_entry(r, &ranges) { + if (fspm_end <= range_entry_base(r)) + continue; + if (fspm_begin >= range_entry_end(r)) + continue; + printk(BIOS_ERR, "FSPM overlaps currently running program.\n"); + return CB_ERR; + } + + /* Load binary into memory at provided address. */ + if (rdev_readat(rdev, (void *)fspm_begin, 0, fspm_end - fspm_begin) < 0) + return CB_ERR; + + return CB_SUCCESS; +} + +/* Handle the case when FSPM is running XIP. */ +static enum cb_err load_fspm_xip(struct fsp_header *hdr, + const struct region_device *rdev) +{ + void *base; + + if (fsp_validate_component(hdr, rdev) != CB_SUCCESS) + return CB_ERR; + + base = rdev_mmap_full(rdev); + if ((uintptr_t)base != hdr->image_base) { + printk(BIOS_ERR, "FSPM XIP base does not match: %p vs %p\n", + (void *)(uintptr_t)hdr->image_base, base); + return CB_ERR; + } + + /* + * Since the component is XIP it's already in the address space. Thus, + * there's no need to rdev_munmap(). + */ + return CB_SUCCESS; +} + +enum fsp_status fsp_memory_init(bool s3wake) { struct fsp_header hdr; + enum cb_err status; + struct cbfsf file_desc; + struct region_device file_data; + const char *name = CONFIG_FSP_M_CBFS; - if (fsp_load_binary(&hdr, CONFIG_FSP_M_CBFS, range) != CB_SUCCESS) + if (cbfs_boot_locate(&file_desc, name, NULL)) { + printk(BIOS_ERR, "Could not locate %s in CBFS\n", name); return FSP_NOT_FOUND; + } + + cbfs_file_data(&file_data, &file_desc); + + if (IS_ENABLED(CONFIG_NO_XIP_EARLY_STAGES)) + status = load_fspm_mem(&hdr, &file_data); + else + status = load_fspm_xip(&hdr, &file_data); + + if (status != CB_SUCCESS) { + printk(BIOS_ERR, "Loading FSPM failed.\n"); + return FSP_NOT_FOUND; + } + + /* Signal that FSP component has been loaded. */ + prog_segment_loaded(hdr.image_base, hdr.image_size, SEG_FINAL); return do_fsp_memory_init(&hdr, s3wake); } -- cgit v1.2.3