soc/intel/common/fast_spi: Add custom boot media device

This change enables support for a custom boot media device in fast SPI
controller driver if the platform supports additional decode window
for mapping BIOS regions greater than 16MiB. Following new Kconfigs
are added:
1. FAST_SPI_SUPPORTS_EXT_BIOS_WINDOW: SoC can select this to indicate
support for extended BIOS window.
2. EXT_BIOS_WIN_BASE: If FAST_SPI_SUPPORTS_EXT_BIOS_WINDOW is
selected, this provides the base address of the host space that is
reserved for mapping the extended window.
3. EXT_BIOS_WIN_SIZE: If FAST_SPI_SUPPORTS_EXT_BIOS_WINDOW is
selected, this provides the size of the host space reserved for
mapping extended window.

If platform indicates support for extended BIOS decode window,
cbfstool add command is provided additional parameters for the decode
window using --ext-win-base and --ext-win-size.

It is the responsibility of the mainboard fmap author to ensure that
the sections in the BIOS region do not cross 16MiB boundary as the
host space windows are not contiguous. This change adds a build time
check to ensure no sections in FMAP cross the 16MiB boundary.

Even though the platform supports extended window, it depends upon the
size of BIOS region (which in turn depends on SPI flash size) whether
and how much of the additional window is utilized at runtime. This
change also provides helper functions for rest of the coreboot
components to query how much of the extended window is actually
utilized.

BUG=b:171534504

Change-Id: I1b564aed9809cf14b40a3b8e907622266fc782e2
Signed-off-by: Furquan Shaikh <furquan@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/47659
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
This commit is contained in:
Furquan Shaikh 2020-11-22 11:37:44 -08:00
parent b652aaef99
commit 886f4e862a
4 changed files with 246 additions and 0 deletions

View File

@ -11,3 +11,48 @@ config FAST_SPI_DISABLE_WRITE_STATUS
default y default y
help help
Disable the write status SPI opcode in Intel Fast SPI block. Disable the write status SPI opcode in Intel Fast SPI block.
config FAST_SPI_SUPPORTS_EXT_BIOS_WINDOW
bool
depends on SOC_INTEL_COMMON_BLOCK_FAST_SPI
help
Fast SPI controller on the platform supports additional
window for memory mapping BIOS region (region 1) on the SPI
flash beyond the standard limit of 16MiB. Depending upon the
size of the SPI flash part used by the mainboard, two decode
windows will be enabled:
1. Fixed decode window up to a maximum size of 16MiB under
4G boundary.
2. Extended decode window up to a maximum size provided by
the platform to map the rest of the BIOS region.
SoC selecting this config is expected to provide the base and
maximum size of the extended window in the host address space
using configs EXT_BIOS_WIN_BASE and EXT_BIOS_WIN_SIZE.
config EXT_BIOS_WIN_BASE
hex
help
If an additional window for mapping BIOS region greater than
16MiB is supported, then this config is used to provide the
base address reserved for the mapping. Since the mapping is
done at the top of the window, depending upon the size of the
BIOS region, the actual base address configured in the fast
SPI controller can be higher at runtime.
config EXT_BIOS_WIN_SIZE
hex
help
Maximum size of the extended window reserved for mapping BIOS
region greater than 16MiB. The actual mapped window might be
smaller depending upon the size of the BIOS region.
if FAST_SPI_SUPPORTS_EXT_BIOS_WINDOW
# Disable X86_TOP4G_BOOTMEDIA_MAP because the fast SPI controller
# driver provides a custom boot media device when multiple decode
# windows are used for the BIOS region.
config X86_TOP4G_BOOTMEDIA_MAP
default n
endif

View File

@ -19,3 +19,35 @@ smm-$(CONFIG_SOC_INTEL_COMMON_BLOCK_FAST_SPI) += fast_spi_flash.c
endif endif
CPPFLAGS_common += -I$(src)/soc/intel/common/block/fast_spi CPPFLAGS_common += -I$(src)/soc/intel/common/block/fast_spi
ifeq ($(CONFIG_FAST_SPI_SUPPORTS_EXT_BIOS_WINDOW),y)
# mmap_boot.c provides a custom boot media device for the platforms that support
# additional window for BIOS regions greater than 16MiB. This is used instead of
# the default boot media device in arch/x86/mmap_boot.c
bootblock-y += mmap_boot.c
verstage-y += mmap_boot.c
romstage-y += mmap_boot.c
postcar-y += mmap_boot.c
ramstage-y += mmap_boot.c
smm-y += mmap_boot.c
# Check to ensure that no sections in the FMAP cross 16MiB boundary if
# the platform supports split decode windows for BIOS region greater
# than 16MiB.
check-fmap-16mib-crossing: $(obj)/fmap_config.h
flash_offset=$$(printf "%d" $$(cat $(obj)/fmap_config.h | grep "FMAP_SECTION_FLASH_START" | awk '{print $$NF}')); \
for x in $$(cat $(obj)/fmap_config.h | grep "FMAP_TERMINAL_SECTIONS" | cut -d\" -f2); do \
start=$$(printf "%d" $$(cat $(obj)/fmap_config.h | grep "FMAP_SECTION_"$$x"_START" | awk '{print $$NF}')); \
size=$$(printf "%d" $$(cat $(obj)/fmap_config.h | grep "FMAP_SECTION_"$$x"_SIZE" | awk '{print $$NF}')); \
start=$$((start-flash_offset)); \
end=$$((start+size-1)); \
if [ $$start -lt 16777216 ] && [ $$end -ge 16777216 ]; then echo "ERROR:" $$x "crosses 16MiB boundary"; fail=1; break; fi; \
done; \
if [ $$fail -eq 1 ]; then false; fi
INTERMEDIATE+=check-fmap-16mib-crossing
CBFSTOOL_ADD_CMD_OPTIONS += --ext-win-base $(CONFIG_EXT_BIOS_WIN_BASE) --ext-win-size $(CONFIG_EXT_BIOS_WIN_SIZE)
endif # CONFIG_FAST_SPI_SUPPORTS_EXT_BIOS_WINDOW

View File

@ -0,0 +1,162 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* This file provides a custom boot media device for the platforms that support additional
* window for BIOS regions greater than 16MiB. If the mainboard uses a smaller BIOS region, then
* the additional window is unused.
*/
#include <boot_device.h>
#include <commonlib/region.h>
#include <console/console.h>
#include <fmap.h>
#include <intelblocks/fast_spi.h>
enum window_type {
/* Fixed decode window of max 16MiB size just below 4G boundary */
FIXED_DECODE_WINDOW,
/* Additional decode window for mapping BIOS region greater than 16MiB */
EXT_BIOS_DECODE_WINDOW,
TOTAL_DECODE_WINDOWS,
};
static struct xlate_region_device real_dev;
static struct mem_region_device shadow_devs[TOTAL_DECODE_WINDOWS];
static struct xlate_window real_dev_windows[TOTAL_DECODE_WINDOWS];
static void initialize_window(enum window_type type, uintptr_t host_base,
uintptr_t flash_base, size_t size)
{
mem_region_device_ro_init(&shadow_devs[type], (void *)host_base, size);
xlate_window_init(&real_dev_windows[type], &shadow_devs[type].rdev,
flash_base, size);
printk(BIOS_INFO, "MMAP window: SPI flash base=0x%lx, Host base=0x%lx, Size=0x%zx\n",
flash_base, host_base, size);
}
/*
*
* +--------------+
* | |
* | |
* | |
* ^ +------------+--------------------------^--------------------------------+ 0xffffffff
* | | | | | |
* | | | | | |
* | | | + | FIXED |
* | | | fixed_win_size | DECODE |
* | | BIOS | + | WINDOW |
* + | region | | | |
* bios_size | (Region 1) | | | |
* + | | | | |
* | | | | | |
* | | | fixed_win_flash_base+----v--------------------------------+ fixed_win_host_base
* | | | | | |
* | | | | | |
* | | | | | Other MMIO |
* v | | | | |
* bios_start +------------+ ext_win_flash_base | | |
* | | + | | |
* | | | | | |
* | | | | | |
* | | | +-----^------------------------------------------------------------^
* 0 +------------+ | | | | |
* | + | EXT_BIOS | |
* SPI flash | ext_win_size | DECODE | |
* address | + | WINDOW | +
* space | | | | CONFIG_EXT_BIOS_WIN_SIZE
* +--------------v-------------------------------+ ext_win_host_base +
* | | |
* | Unused | |
* | | |
* +--------------+ CONFIG_EXT_BIOS_WIN_BASE+--v
* | |
* | |
* | |
* +--------------+
*
* Host address
* space
*/
static void bios_mmap_init(void)
{
static bool init_done;
size_t bios_size, bios_start;
uintptr_t fixed_win_host_base, fixed_win_flash_base;
uintptr_t ext_win_host_base, ext_win_flash_base;
size_t fixed_win_size, ext_win_size;
size_t win_count = 0;
if (init_done)
return;
/* Read the offset and size of BIOS region in the SPI flash address space. */
bios_start = fast_spi_get_bios_region(&bios_size);
/*
* By default, fixed decode window (maximum size 16MiB) is mapped just below the 4G
* boundary. This window maps the top part of the BIOS region in the SPI flash address
* space to the host address space.
*/
fixed_win_size = MIN(16 * MiB, bios_size);
fixed_win_host_base = 4ULL * GiB - fixed_win_size;
fixed_win_flash_base = bios_start + bios_size - fixed_win_size;
initialize_window(FIXED_DECODE_WINDOW, fixed_win_host_base, fixed_win_flash_base,
fixed_win_size);
win_count++;
_Static_assert(CONFIG_EXT_BIOS_WIN_BASE != 0, "Extended BIOS window base cannot be 0!");
_Static_assert(CONFIG_EXT_BIOS_WIN_SIZE != 0, "Extended BIOS window size cannot be 0!");
/*
* Remaining portion of the BIOS region up to a maximum of CONFIG_EXT_BIOS_WIN_SIZE is
* mapped at the top of the extended window if the BIOS region is greater than 16MiB.
*
* If the BIOS region is not greater than 16MiB, then the extended window is not
* enabled.
*/
ext_win_size = MIN(CONFIG_EXT_BIOS_WIN_SIZE, bios_size - fixed_win_size);
if (ext_win_size) {
ext_win_host_base = CONFIG_EXT_BIOS_WIN_BASE + CONFIG_EXT_BIOS_WIN_SIZE -
ext_win_size;
ext_win_flash_base = fixed_win_flash_base - ext_win_size;
initialize_window(EXT_BIOS_DECODE_WINDOW, ext_win_host_base,
ext_win_flash_base, ext_win_size);
win_count++;
}
xlate_region_device_ro_init(&real_dev, win_count, real_dev_windows, CONFIG_ROM_SIZE);
init_done = true;
}
const struct region_device *boot_device_ro(void)
{
bios_mmap_init();
return &real_dev.rdev;
}
void fast_spi_get_ext_bios_window(uintptr_t *base, size_t *size)
{
const struct region_device *rd = &shadow_devs[EXT_BIOS_DECODE_WINDOW].rdev;
bios_mmap_init();
*size = region_device_sz(rd);
if (*size == 0) {
*base = 0;
} else {
/*
* This is a memory region device. So, mmap returns the base address of the
* device. Also, as this is a memory region device, unmap is a no-op.
*/
*base = (uintptr_t)rdev_mmap_full(rd);
}
}

View File

@ -74,4 +74,11 @@ bool fast_spi_wpd_status(void);
*/ */
void fast_spi_enable_wp(void); void fast_spi_enable_wp(void);
/*
* Get base and size of extended BIOS decode window used at runtime in host address space. If
* the BIOS region is not greater than 16MiB, then this function returns 0 for both base and
* size.
*/
void fast_spi_get_ext_bios_window(uintptr_t *base, size_t *size);
#endif /* SOC_INTEL_COMMON_BLOCK_FAST_SPI_H */ #endif /* SOC_INTEL_COMMON_BLOCK_FAST_SPI_H */