Furquan Shaikh has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/47882 )
Change subject: util/cbfstool: Add support for mapping extended window for x86 platforms
......................................................................
util/cbfstool: Add support for mapping extended window for x86 platforms
All x86 platforms until now have memory mapped up to a maximum of
16MiB of SPI flash just below 4G boundary in host address space. For
newer platforms, cbfstool needs to be able to accommodate additional
windows in the host address space for mapping SPI flash size greater
than 16MiB.
This change adds two input parameters to cbfstool ext-win-base and
ext-win-size which a platform can use to provide the details of the
extended window in host address space. The extended window does not
necessarily have to be contiguous with the standard decode window
below 4G. But, it is left upto the platform to ensure that the fmap
sections are defined such that they do not cross the window boundary.
create_mmap_windows() uses the input parameters from the platform for
the extended window and the flash size to determine if extended mmap
window is used. If the entire window in host address space is not
covered by the SPI flash region below the top 16MiB, then mapping is
assumed to be done at the top of the extended window in host space.
BUG=b:171534504
Change-Id: Ie8f95993e9c690e34b0e8e792f9881c81459c6b6
Signed-off-by: Furquan Shaikh <furquan(a)google.com>
---
M util/cbfstool/cbfstool.c
1 file changed, 90 insertions(+), 8 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/82/47882/1
diff --git a/util/cbfstool/cbfstool.c b/util/cbfstool/cbfstool.c
index c0f13e7..86bc866 100644
--- a/util/cbfstool/cbfstool.c
+++ b/util/cbfstool/cbfstool.c
@@ -93,6 +93,18 @@
char *initrd;
char *cmdline;
int force;
+ /*
+ * Base and size of extended window for decoding SPI flash greater than 16MiB in host
+ * address space on x86 platforms. The assumptions here are:
+ * 1. Top 16MiB is still decoded in the fixed decode window just below 4G boundary.
+ * 2. Rest of the SPI flash below the top 16MiB is mapped at the top of extended
+ * window. Even though the platform might support a larger extended window, the SPI
+ * flash part used by the mainboard might not be large enough to be mapped in the entire
+ * window. In such cases, the mapping is assumed to be in the top part of the extended
+ * window with the bottom part remaining unused.
+ */
+ uint32_t ext_win_base;
+ uint32_t ext_win_size;
} param = {
/* All variables not listed are initialized as zero. */
.arch = CBFS_ARCHITECTURE_UNKNOWN,
@@ -124,6 +136,8 @@
enum mmap_window_type {
X86_DEFAULT_DECODE_WINDOW, /* Decode window just below 4G boundary */
+ X86_EXTENDED_DECODE_WINDOW, /* Extended decode window for mapping greater than 16MiB
+ flash */
MMAP_MAX_WINDOWS,
};
@@ -145,25 +159,69 @@
mmap_window_table[idx].host_space.size = window_size;
}
-static void create_mmap_windows(void)
+static bool create_mmap_windows(void)
{
static bool done;
if (done)
- return;
+ return done;
const size_t image_size = partitioned_file_total_size(param.image_file);
- const size_t window_size = MIN(16 * MiB, image_size);
+ const size_t std_window_size = MIN(16 * MiB, image_size);
+ const size_t std_window_flash_offset = image_size - std_window_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);
+ add_mmap_window(X86_DEFAULT_DECODE_WINDOW, std_window_flash_offset,
+ 4ULL * GiB - std_window_size, std_window_size);
+
+ if (param.ext_win_size && (image_size > 16 * MiB)) {
+ /*
+ * If the platform supports extended window and the SPI flash size is greater
+ * than 16MiB, then create a mapping for the extended window as well.
+ * The assumptions here are:
+ * 1. Top 16MiB is still decoded in the fixed decode window just below 4G
+ * boundary.
+ * 2. Rest of the SPI flash below the top 16MiB is mapped at the top of extended
+ * window. Even though the platform might support a larger extended window, the
+ * SPI flash part used by the mainboard might not be large enough to be mapped
+ * in the entire window. In such cases, the mapping is assumed to be in the top
+ * part of the extended window with the bottom part remaining unused.
+ *
+ * Example:
+ * ext_win_base = 0xF8000000
+ * ext_win_size = 32 * MiB
+ * ext_win_limit = ext_win_base + ext_win_size - 1 = 0xF9FFFFFF
+ *
+ * If SPI flash is 32MiB, then top 16MiB is mapped from 0xFF000000 - 0xFFFFFFFF
+ * whereas the bottom 16MiB is mapped from 0xF9000000 - 0xF9FFFFFF. The extended
+ * window 0xF8000000 - 0xF8FFFFFF remains unused.
+ */
+ const size_t ext_window_mapped_size = MIN(param.ext_win_size,
+ image_size - std_window_size);
+ const size_t ext_window_top = param.ext_win_base + param.ext_win_size;
+ add_mmap_window(X86_EXTENDED_DECODE_WINDOW,
+ std_window_flash_offset - ext_window_mapped_size,
+ ext_window_top - ext_window_mapped_size,
+ ext_window_mapped_size);
+
+ if (region_overlap(&mmap_window_table[X86_EXTENDED_DECODE_WINDOW].host_space,
+ &mmap_window_table[X86_DEFAULT_DECODE_WINDOW].host_space)) {
+ const struct region *ext_region;
+
+ ext_region = &mmap_window_table[X86_EXTENDED_DECODE_WINDOW].host_space;
+ ERROR("Extended window(base=0x%zx, limit=0x%zx) overlaps with default window!\n",
+ region_offset(ext_region), region_end(ext_region));
+
+ return false;
+ }
+ }
done = true;
+ return done;
}
static unsigned int convert_address(const struct region *to, const struct region *from,
@@ -236,7 +294,7 @@
{
assert(region);
- create_mmap_windows();
+ assert(create_mmap_windows());
if (IS_HOST_SPACE_ADDRESS(addr))
return convert_host_to_flash(region, addr);
@@ -1410,6 +1468,8 @@
/* begin after ASCII characters */
LONGOPT_START = 256,
LONGOPT_IBB = LONGOPT_START,
+ LONGOPT_EXT_WIN_BASE,
+ LONGOPT_EXT_WIN_SIZE,
LONGOPT_END,
};
@@ -1453,6 +1513,8 @@
{"mach-parseable",no_argument, 0, 'k' },
{"unprocessed", no_argument, 0, 'U' },
{"ibb", no_argument, 0, LONGOPT_IBB },
+ {"ext-win-base", required_argument, 0, LONGOPT_EXT_WIN_BASE },
+ {"ext-win-size", required_argument, 0, LONGOPT_EXT_WIN_SIZE },
{NULL, 0, 0, 0 }
};
@@ -1543,11 +1605,16 @@
" -U Unprocessed; don't decompress or make ELF\n"
" -v Provide verbose output\n"
" -h Display this help message\n\n"
+ " --ext-win-base Base of extended decode window in host address\n"
+ " space(x86 only)\n"
+ " --ext-win-size Size of extended decode window in host address\n"
+ " space(x86 only)\n"
"COMMANDs:\n"
" add [-r image,regions] -f FILE -n NAME -t TYPE [-A hash] \\\n"
" [-c compression] [-b base-address | -a alignment] \\\n"
" [-p padding size] [-y|--xip if TYPE is FSP] \\\n"
- " [-j topswap-size] (Intel CPUs only) [--ibb] "
+ " [-j topswap-size] (Intel CPUs only) [--ibb] \\\n"
+ " [--ext-win-base win-base --ext-win-size win-size] "
"Add a component\n"
" "
" -j valid size: 0x10000 0x20000 0x40000 0x80000 0x100000 \n"
@@ -1558,7 +1625,8 @@
" add-stage [-r image,regions] -f FILE -n NAME [-A hash] \\\n"
" [-c compression] [-b base] [-S section-to-ignore] \\\n"
" [-a alignment] [-P page-size] [-Q|--pow2page] \\\n"
- " [-y|--xip] [--ibb] "
+ " [-y|--xip] [--ibb] \\\n"
+ " [--ext-win-base win-base --ext-win-size win-size] "
"Add a stage to the ROM\n"
" add-flat-binary [-r image,regions] -f FILE -n NAME \\\n"
" [-A hash] -l load-address -e entry-point \\\n"
@@ -1890,6 +1958,20 @@
case LONGOPT_IBB:
param.ibb = true;
break;
+ case LONGOPT_EXT_WIN_BASE:
+ param.ext_win_base = strtoul(optarg, &suffix, 0);
+ if (!*optarg || (suffix && *suffix)) {
+ ERROR("Invalid ext window base '%s'.\n", optarg);
+ return 1;
+ }
+ break;
+ case LONGOPT_EXT_WIN_SIZE:
+ param.ext_win_size = strtoul(optarg, &suffix, 0);
+ if (!*optarg || (suffix && *suffix)) {
+ ERROR("Invalid ext window size '%s'.\n", optarg);
+ return 1;
+ }
+ break;
case 'h':
case '?':
usage(argv[0]);
--
To view, visit https://review.coreboot.org/c/coreboot/+/47882
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: Ie8f95993e9c690e34b0e8e792f9881c81459c6b6
Gerrit-Change-Number: 47882
Gerrit-PatchSet: 1
Gerrit-Owner: Furquan Shaikh <furquan(a)google.com>
Gerrit-MessageType: newchange
Furquan Shaikh has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/47830 )
Change subject: util/cbfstool: Rename IS_TOP_ALIGNED_ADDRESS to IS_HOST_SPACE_ADDRESS
......................................................................
util/cbfstool: Rename IS_TOP_ALIGNED_ADDRESS to IS_HOST_SPACE_ADDRESS
This change renames the macro `IS_TOP_ALIGNED_ADDRESS` to
`IS_HOST_SPACE_ADDRESS` to make it clear that the macro checks if
given address is an address in the host space as opposed to the SPI
flash space.
Change-Id: I84bb505df62ac41f1d364a662be145603c0bd5fa
Signed-off-by: Furquan Shaikh <furquan(a)google.com>
---
M util/cbfstool/cbfs_image.c
M util/cbfstool/cbfstool.c
M util/cbfstool/common.h
3 files changed, 9 insertions(+), 4 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/30/47830/1
diff --git a/util/cbfstool/cbfs_image.c b/util/cbfstool/cbfs_image.c
index 3f1bf43..da65960 100644
--- a/util/cbfstool/cbfs_image.c
+++ b/util/cbfstool/cbfs_image.c
@@ -731,7 +731,7 @@
assert(image);
assert(buffer);
assert(buffer->data);
- assert(!IS_TOP_ALIGNED_ADDRESS(content_offset));
+ assert(!IS_HOST_SPACE_ADDRESS(content_offset));
const char *name = header->filename;
diff --git a/util/cbfstool/cbfstool.c b/util/cbfstool/cbfstool.c
index c719b8f..061ff82 100644
--- a/util/cbfstool/cbfstool.c
+++ b/util/cbfstool/cbfstool.c
@@ -563,7 +563,7 @@
return -1;
}
- if (IS_TOP_ALIGNED_ADDRESS(offset))
+ if (IS_HOST_SPACE_ADDRESS(offset))
offset = convert_to_from_absolute_top_aligned(param.image_region,
-offset);
if (cbfs_add_entry(&image, &buffer, offset, header, len_align) != 0) {
@@ -646,7 +646,7 @@
* passed in by the caller.
*/
if (param.stage_xip) {
- if (!IS_TOP_ALIGNED_ADDRESS(address))
+ if (!IS_HOST_SPACE_ADDRESS(address))
address = -convert_to_from_absolute_top_aligned(
param.image_region, address);
} else {
diff --git a/util/cbfstool/common.h b/util/cbfstool/common.h
index 7dbc1f5..9f62e77 100644
--- a/util/cbfstool/common.h
+++ b/util/cbfstool/common.h
@@ -15,7 +15,12 @@
/* Endianness */
#include "swab.h"
-#define IS_TOP_ALIGNED_ADDRESS(x) ((uint32_t)(x) > 0x80000000)
+/*
+ * There are two address spaces that this tool deals with - SPI flash address space and host
+ * address space. This macros checks if the address is greater than 2GiB under the assumption
+ * that the low MMIO lives in the top half of the 4G address space of the host.
+ */
+#define IS_HOST_SPACE_ADDRESS(addr) ((uint32_t)(addr) > 0x80000000)
#define unused __attribute__((unused))
--
To view, visit https://review.coreboot.org/c/coreboot/+/47830
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I84bb505df62ac41f1d364a662be145603c0bd5fa
Gerrit-Change-Number: 47830
Gerrit-PatchSet: 1
Gerrit-Owner: Furquan Shaikh <furquan(a)google.com>
Gerrit-MessageType: newchange
Furquan Shaikh has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/47829 )
Change subject: util/cbfstool: Treat region offsets differently than absolute addresses
......................................................................
util/cbfstool: Treat region offsets differently than absolute addresses
cbfstool overloads baseaddress to represent multiple things:
1. Address in SPI flash space
2. Address in host space (for x86 platforms)
3. Offset from end of region (accepted as negative number)
This was done so that the different functions that use these
addresses/offsets don't need to be aware of what the value represents
and can use the helper functions convert_to_from* to get the required
values.
Thus, even if the user provides a negative value to represent offset
from end of region, it was stored as an unsigned integer. There are
special checks in convert_to_from_top_aligned which guesses if the
value provided is really an offset from the end of region and converts
it to an offset from start of region.
This has worked okay until now for x86 platforms because there is a
single fixed decode window mapping the SPI flash to host address
space. However, going forward new platforms might need to support more
decode windows that are not contiguous in the host space. Thus, it is
important to distinguish between offsets from end of region and
addresses in host/SPI flash space and treat them separately.
As a first step towards supporting this requirement for multiple
decode windows on new platforms, this change handles the negative
offset provided as input in dispatch_command before the requested cbfs
operation is performed.
This change adds baseaddress_input, headeroffset_input and
cbfsoffset_input to struct param and converts them to offsets from
start of region before storing into baseaddress, headeroffset and
cbfsoffset if the inputs are negative.
In follow up changes, cbfstool will be extended to add support
for multiple decode windows.
TEST=Verified using abuild with timeless option for all coreboot
boards that there is no change in the resultant coreboot.rom file.
Change-Id: Ib74a7e6ed9e88fbc5489640d73bedac14872953f
Signed-off-by: Furquan Shaikh <furquan(a)google.com>
---
M util/cbfstool/cbfs_image.c
M util/cbfstool/cbfstool.c
2 files changed, 54 insertions(+), 41 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/29/47829/1
diff --git a/util/cbfstool/cbfs_image.c b/util/cbfstool/cbfs_image.c
index a042f0d..3f1bf43 100644
--- a/util/cbfstool/cbfs_image.c
+++ b/util/cbfstool/cbfs_image.c
@@ -277,14 +277,6 @@
bootblock_offset, bootblock->size, header_offset,
sizeof(image->header), entries_offset);
- // Adjust legacy top-aligned address to ROM offset.
- if (IS_TOP_ALIGNED_ADDRESS(entries_offset))
- entries_offset = size + (int32_t)entries_offset;
- if (IS_TOP_ALIGNED_ADDRESS(bootblock_offset))
- bootblock_offset = size + (int32_t)bootblock_offset;
- if (IS_TOP_ALIGNED_ADDRESS(header_offset))
- header_offset = size + (int32_t)header_offset;
-
DEBUG("cbfs_create_image: (real offset) bootblock=0x%x, "
"header=0x%x, entries_offset=0x%x\n",
bootblock_offset, header_offset, entries_offset);
diff --git a/util/cbfstool/cbfstool.c b/util/cbfstool/cbfstool.c
index d2df1cc..c719b8f 100644
--- a/util/cbfstool/cbfstool.c
+++ b/util/cbfstool/cbfstool.c
@@ -47,15 +47,22 @@
uint64_t u64val;
uint32_t type;
uint32_t baseaddress;
+ /*
+ * Input can be negative. It will be transformed to corresponding region offset and
+ * stored in baseaddress.
+ */
+ long long int baseaddress_input;
uint32_t baseaddress_assigned;
uint32_t loadaddress;
uint32_t headeroffset;
+ long long int headeroffset_input;
uint32_t headeroffset_assigned;
uint32_t entrypoint;
uint32_t size;
uint32_t alignment;
uint32_t pagesize;
uint32_t cbfsoffset;
+ long long int cbfsoffset_input;
uint32_t cbfsoffset_assigned;
uint32_t arch;
uint32_t padding;
@@ -102,8 +109,7 @@
/*
* Converts between offsets from the start of the specified image region and
- * "top-aligned" offsets from the top of the entire boot media. See comment
- * below for convert_to_from_top_aligned() about forming addresses.
+ * "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)
@@ -116,25 +122,26 @@
}
/*
- * Converts between offsets from the start of the specified image region and
- * "top-aligned" offsets from the top of the image region. Works in either
- * direction: pass in one type of offset and receive the other type.
- * N.B. A top-aligned offset is always a positive number, and should not be
- * confused with a top-aligned *address*, which is its arithmetic inverse. */
-static unsigned convert_to_from_top_aligned(const struct buffer *region,
- unsigned offset)
+ * This function takes offset value which represents the offset from one end of the region and
+ * returns the offset from the other end of the region. offset is expected to be positive.
+ */
+static unsigned convert_region_offset(unsigned offset)
{
- assert(region);
+ size_t size;
- /* Cover the situation where a negative base address is given by the
- * user. Callers of this function negate it, so it'll be a positive
- * number smaller than the region.
- */
- if ((offset > 0) && (offset < region->size)) {
- return region->size - offset;
+ if (param.size) {
+ size = param.size;
+ } else {
+ assert(param.image_region);
+ size = param.image_region->size;
}
- return convert_to_from_absolute_top_aligned(region, offset);
+ if (size < offset) {
+ ERROR("Cannot convert region offset (size=0x%zx, offset=0x%x\n", size, offset);
+ return 0;
+ }
+
+ return size - offset;
}
static int do_cbfs_locate(int32_t *cbfs_addr, size_t metadata_size,
@@ -242,10 +249,6 @@
goto done;
}
- if (IS_TOP_ALIGNED_ADDRESS(offset))
- offset = convert_to_from_top_aligned(param.image_region,
- -offset);
-
header = cbfs_create_file_header(CBFS_COMPONENT_RAW,
buffer.size, name);
if (cbfs_add_entry(&image, &buffer, offset, header, 0) != 0) {
@@ -434,8 +437,7 @@
buffer_clone(buffer, &new_bootblock);
/* Update the location (offset) of bootblock in the region */
- *offset = convert_to_from_top_aligned(param.image_region,
- buffer_size(buffer));
+ *offset = convert_region_offset(buffer_size(buffer));
return 0;
}
@@ -519,11 +521,9 @@
/* to the cbfs file and therefore set the position */
/* the real beginning of the data. */
if (type == CBFS_COMPONENT_STAGE)
- attrs->position = htonl(offset +
- sizeof(struct cbfs_stage));
+ attrs->position = htonl(offset - sizeof(struct cbfs_stage));
else if (type == CBFS_COMPONENT_SELF)
- attrs->position = htonl(offset +
- sizeof(struct cbfs_payload));
+ attrs->position = htonl(offset - sizeof(struct cbfs_payload));
else
attrs->position = htonl(offset);
}
@@ -564,8 +564,8 @@
}
if (IS_TOP_ALIGNED_ADDRESS(offset))
- offset = convert_to_from_top_aligned(param.image_region,
- -offset);
+ offset = convert_to_from_absolute_top_aligned(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);
@@ -1336,6 +1336,16 @@
{NULL, 0, 0, 0 }
};
+static uint32_t get_region_offset(long long int offset)
+{
+ /* If offset is not negative, no transformation required. */
+ if (offset >= 0)
+ return offset;
+
+ /* Calculate offset from start of region. */
+ return convert_region_offset(-offset);
+}
+
static int dispatch_command(struct command command)
{
if (command.accesses_region) {
@@ -1373,6 +1383,17 @@
return 1;
}
}
+
+ /*
+ * Once image region is read, input offsets can be adjusted accordingly if the
+ * inputs are provided as negative integers i.e. offsets from end of region.
+ */
+ if (param.baseaddress_assigned)
+ param.baseaddress = get_region_offset(param.baseaddress_input);
+ if (param.headeroffset_assigned)
+ param.headeroffset = get_region_offset(param.headeroffset_input);
+ if (param.cbfsoffset_assigned)
+ param.cbfsoffset = get_region_offset(param.cbfsoffset_input);
}
if (command.function()) {
@@ -1592,7 +1613,7 @@
param.source_region = optarg;
break;
case 'b':
- param.baseaddress = strtoul(optarg, &suffix, 0);
+ param.baseaddress_input = strtoll(optarg, &suffix, 0);
if (!*optarg || (suffix && *suffix)) {
ERROR("Invalid base address '%s'.\n",
optarg);
@@ -1643,8 +1664,7 @@
param.bootblock = optarg;
break;
case 'H':
- param.headeroffset = strtoul(
- optarg, &suffix, 0);
+ param.headeroffset_input = strtoll(optarg, &suffix, 0);
if (!*optarg || (suffix && *suffix)) {
ERROR("Invalid header offset '%s'.\n",
optarg);
@@ -1680,7 +1700,7 @@
param.force_pow2_pagesize = 1;
break;
case 'o':
- param.cbfsoffset = strtoul(optarg, &suffix, 0);
+ param.cbfsoffset_input = strtoll(optarg, &suffix, 0);
if (!*optarg || (suffix && *suffix)) {
ERROR("Invalid cbfs offset '%s'.\n",
optarg);
@@ -1817,6 +1837,7 @@
seen_primary_cbfs = true;
param.image_region = image_regions + region;
+
if (dispatch_command(commands[i])) {
partitioned_file_close(param.image_file);
return 1;
--
To view, visit https://review.coreboot.org/c/coreboot/+/47829
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: Ib74a7e6ed9e88fbc5489640d73bedac14872953f
Gerrit-Change-Number: 47829
Gerrit-PatchSet: 1
Gerrit-Owner: Furquan Shaikh <furquan(a)google.com>
Gerrit-MessageType: newchange