From 0dcc0662f3c683248f3096f27de269fa0f88d357 Mon Sep 17 00:00:00 2001 From: Furquan Shaikh Date: Fri, 20 Nov 2020 22:51:17 -0800 Subject: util/cbfstool: Introduce concept of mmap_window This change adds the concept of mmap_window to describe how the SPI flash address space is mapped to host address space on x86 platforms. It gets rid of the assumption that the SPI flash address space is mapped only below the 4G boundary in host space. This is required in follow up changes to be able to add more decode windows for the SPI flash into the host address space. Currently, a single mmap window is added i.e. the default x86 decode window of maximum 16MiB size living just below the 4G boundary. If the window is smaller than 16MiB, then it is mapped at the top of the host window. BUG=b:171534504 TEST=Verified using abuild with timeless option for all coreboot boards that there is no change in the resultant coreboot.rom file. Change-Id: I8dd3d1c922cc834c1e67f279ffce8fa438d8209c Signed-off-by: Furquan Shaikh Reviewed-on: https://review.coreboot.org/c/coreboot/+/47831 Tested-by: build bot (Jenkins) Reviewed-by: Tim Wawrzynczak Reviewed-by: Duncan Laurie --- util/cbfstool/cbfstool.c | 154 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 140 insertions(+), 14 deletions(-) (limited to 'util') diff --git a/util/cbfstool/cbfstool.c b/util/cbfstool/cbfstool.c index f9f4e535a9..eca9bcc2bf 100644 --- a/util/cbfstool/cbfstool.c +++ b/util/cbfstool/cbfstool.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #define SECTION_WITH_FIT_TABLE "BOOTBLOCK" @@ -116,18 +117,145 @@ static bool region_is_modern_cbfs(const char *region) CBFS_FILE_MAGIC, strlen(CBFS_FILE_MAGIC)); } -/* - * Converts between offsets from the start of the specified image region and - * "top-aligned" offsets from the top of the entire boot media. - */ -static unsigned convert_to_from_absolute_top_aligned( - const struct buffer *region, unsigned offset) +/* This describes a window from the SPI flash address space into the host address space. */ +struct mmap_window { + struct region flash_space; + struct region host_space; +}; + +enum mmap_window_type { + X86_DEFAULT_DECODE_WINDOW, /* Decode window just below 4G boundary */ + MMAP_MAX_WINDOWS, +}; + +/* Table of all the decode windows supported by the platform. */ +static struct mmap_window mmap_window_table[MMAP_MAX_WINDOWS]; + +static void add_mmap_window(enum mmap_window_type idx, size_t flash_offset, size_t host_offset, + size_t window_size) +{ + if (idx >= MMAP_MAX_WINDOWS) { + ERROR("Incorrect mmap window index(%d)\n", idx); + return; + } + + mmap_window_table[idx].flash_space.offset = flash_offset; + mmap_window_table[idx].host_space.offset = host_offset; + mmap_window_table[idx].flash_space.size = window_size; + mmap_window_table[idx].host_space.size = window_size; +} + +static void create_mmap_windows(void) +{ + static bool done; + + if (done) + return; + + const size_t image_size = partitioned_file_total_size(param.image_file); + const size_t window_size = MIN(16 * MiB, image_size); + + /* + * Default decode window lives just below 4G boundary in host space and maps up to a + * maximum of 16MiB. If the window is smaller than 16MiB, the SPI flash window is mapped + * at the top of the host window just below 4G. + */ + add_mmap_window(X86_DEFAULT_DECODE_WINDOW, image_size - window_size, + 4ULL * GiB - window_size, window_size); + + done = true; +} + +static unsigned int convert_address(const struct region *to, const struct region *from, + unsigned int addr) +{ + /* + * Calculate the offset in the "from" region and use that offset to calculate + * corresponding address in the "to" region. + */ + size_t offset = addr - region_offset(from); + return region_offset(to) + offset; +} + +enum mmap_addr_type { + HOST_SPACE_ADDR, + FLASH_SPACE_ADDR, +}; + +static int find_mmap_window(enum mmap_addr_type addr_type, unsigned int addr) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(mmap_window_table); i++) { + const struct region *reg; + + if (addr_type == HOST_SPACE_ADDR) + reg = &mmap_window_table[i].host_space; + else + reg = &mmap_window_table[i].flash_space; + + if (region_offset(reg) <= addr && region_end(reg) >= addr) + return i; + } + + return -1; +} + +static unsigned int convert_host_to_flash(const struct buffer *region, unsigned int addr) +{ + int idx; + const struct region *to, *from; + + idx = find_mmap_window(HOST_SPACE_ADDR, addr); + if (idx == -1) { + ERROR("Host address(%x) not in any mmap window!\n", addr); + return 0; + } + + to = &mmap_window_table[idx].flash_space; + from = &mmap_window_table[idx].host_space; + + /* region->offset is subtracted because caller expects offset in the given region. */ + return convert_address(to, from, addr) - region->offset; +} + +static unsigned int convert_flash_to_host(const struct buffer *region, unsigned int addr) +{ + int idx; + const struct region *to, *from; + + /* + * region->offset is added because caller provides offset in the given region. This is + * converted to an absolute address in the SPI flash space. This is done before the + * conversion as opposed to after in convert_host_to_flash() above because the address + * is actually an offset within the region. So, it needs to be converted into an + * absolute address in the SPI flash space before converting into an address in host + * space. + */ + addr += region->offset; + idx = find_mmap_window(FLASH_SPACE_ADDR, addr); + + if (idx == -1) { + ERROR("SPI flash address(%x) not in any mmap window!\n", addr); + return 0; + } + + to = &mmap_window_table[idx].host_space; + from = &mmap_window_table[idx].flash_space; + + return convert_address(to, from, addr); +} + +static unsigned int convert_addr_space(const struct buffer *region, unsigned int addr) { assert(region); - size_t image_size = partitioned_file_total_size(param.image_file); + create_mmap_windows(); - return image_size - region->offset - offset; + if (IS_HOST_SPACE_ADDRESS(addr)) + return convert_host_to_flash(region, addr); + else + return convert_flash_to_host(region, addr); } /* @@ -572,7 +700,8 @@ static int cbfs_add_component(const char *filename, } if (IS_HOST_SPACE_ADDRESS(offset)) - offset = convert_to_from_absolute_top_aligned(param.image_region, -offset); + offset = convert_addr_space(param.image_region, offset); + if (cbfs_add_entry(&image, &buffer, offset, header, len_align) != 0) { ERROR("Failed to add '%s' into ROM image.\n", filename); free(header); @@ -658,8 +787,7 @@ static int cbfstool_convert_fsp(struct buffer *buffer, */ if (param.stage_xip) { if (!IS_HOST_SPACE_ADDRESS(address)) - address = -convert_to_from_absolute_top_aligned( - param.image_region, address); + address = convert_addr_space(param.image_region, address); } else { if (param.baseaddress_assigned == 0) { INFO("Honoring pre-linked FSP module.\n"); @@ -732,9 +860,7 @@ static int cbfstool_convert_mkstage(struct buffer *buffer, uint32_t *offset, * x86 semantics about the boot media being directly mapped * below 4GiB in the CPU address space. **/ - address = -convert_to_from_absolute_top_aligned( - param.image_region, address); - *offset = address; + *offset = convert_addr_space(param.image_region, address); ret = parse_elf_to_xip_stage(buffer, &output, offset, param.ignore_section); -- cgit v1.2.3