Arthur Heymans has uploaded this change for review.

View Change

sb/intel/common: Get memory map from SPI controller

Instead of always assuming that the top of a flash matches the top of 4G
use the real memory map that's configured in the IFD and is reflected in
the SPI registers.

One possible use case is to cleanly generate images for some hacks
rather than having to apply some 'dd' trickery: e.g. on HP Sure Start a
part of the flash is checked by EC.

UNTESTED. This might break some hacks people use to work around SPI
locked images by modifying the IFD when booted with a recovery strap
pulled. Those would also need a specifically crafted FMAP.

Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Change-Id: I5f31c175345ec3efab02255a7063054eb0ad29e4
---
M src/southbridge/intel/common/Kconfig.common
M src/southbridge/intel/common/Makefile.inc
M src/southbridge/intel/common/rcba.h
A src/southbridge/intel/common/spi_memmap.c
4 files changed, 86 insertions(+), 0 deletions(-)

git pull ssh://review.coreboot.org:29418/coreboot refs/changes/80/79880/1
diff --git a/src/southbridge/intel/common/Kconfig.common b/src/southbridge/intel/common/Kconfig.common
index e138f5e..ede5c06 100644
--- a/src/southbridge/intel/common/Kconfig.common
+++ b/src/southbridge/intel/common/Kconfig.common
@@ -33,6 +33,12 @@
select SPI_FLASH
select BOOT_DEVICE_SUPPORTS_WRITES

+config SOUTHBRIDGE_INTEL_COMMON_SPI_IFD_MMAP
+ def_bool y
+ depends on SOUTHBRIDGE_INTEL_COMMON_SPI && (!SOUTHBRIDGE_INTEL_COMMON_SPI_ICH7 || !SOUTHBRIDGE_INTEL_COMMON_SPI_SILVERMONT)
+ select SPI_FLASH
+ select X86_CUSTOM_BOOTMEDIA
+
config SOUTHBRIDGE_INTEL_COMMON_SPI_ICH7
def_bool n
select SOUTHBRIDGE_INTEL_COMMON_SPI
diff --git a/src/southbridge/intel/common/Makefile.inc b/src/southbridge/intel/common/Makefile.inc
index 2f4c777..2ad042d 100644
--- a/src/southbridge/intel/common/Makefile.inc
+++ b/src/southbridge/intel/common/Makefile.inc
@@ -53,3 +53,6 @@
smm-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_FINALIZE) += finalize.c

all-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_RTC) += rtc.c
+
+all-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_SPI_IFD_MMAP) += spi_memmap.c
+smm-$(CONFIG_SOUTHBRIDGE_INTEL_COMMON_SPI_IFD_MMAP) += spi_memmap.c
diff --git a/src/southbridge/intel/common/rcba.h b/src/southbridge/intel/common/rcba.h
index 4a9847a..e079c43 100644
--- a/src/southbridge/intel/common/rcba.h
+++ b/src/southbridge/intel/common/rcba.h
@@ -9,6 +9,9 @@
#define RCBA 0xf0
#define RCBA_ENABLE 0x01

+/* RCBA registers */
+#define RCBA_GCS 0x4310
+
#define RCBA8(x) (*((volatile u8 *)(DEFAULT_RCBA + (x))))
#define RCBA16(x) (*((volatile u16 *)(DEFAULT_RCBA + (x))))
#define RCBA32(x) (*((volatile u32 *)(DEFAULT_RCBA + (x))))
diff --git a/src/southbridge/intel/common/spi_memmap.c b/src/southbridge/intel/common/spi_memmap.c
new file mode 100644
index 0000000..e29df27
--- /dev/null
+++ b/src/southbridge/intel/common/spi_memmap.c
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <assert.h>
+#include <boot_device.h>
+#include <device/device.h>
+#include <fmap_config.h>
+#include <southbridge/intel/common/rcba.h>
+#include <spi_flash.h>
+
+/*
+ * The ROM is memory mapped just below 4GiB. Form a pointer for the base.
+ * At most 16MB is mapped.
+ */
+#define rom_base ((void *)(uintptr_t)(0x100000000ULL-MIN(CONFIG_ROM_SIZE, 16 * MiB)))
+
+#define SPIBAR_BASE 0x3800
+#define BFPR 0x0
+
+union bfpr {
+ uint32_t raw;
+ struct {
+ uint32_t prb : 13;
+ uint32_t _reserved : 3;
+ uint32_t prl : 13;
+ uint32_t _reserved2: 3;
+ };
+};
+
+static uint32_t bios_flash_base;
+static uint32_t bios_size;
+
+static void ich_boot_device_init(struct mem_region_device *boot_dev)
+{
+ const uint32_t gcs = RCBA32(RCBA_GCS);
+
+ const bool spi_boot = ((gcs >> 10) & 3) == 3;
+ if (!spi_boot)
+ return;
+
+ const union bfpr bfpr = { .raw = RCBA32(SPIBAR_BASE + BFPR) };
+ bios_flash_base = bfpr.prb << 12;
+
+ const uint32_t bios_flash_limit = (bfpr.prl << 12) + 0xfff;
+ bios_size = bios_flash_limit + 1 - bios_flash_base;
+ /* Do some basic validation of FMAP */
+ assert(FMAP_SECTION_COREBOOT_START - FMAP_SECTION_FLASH_START
+ + FMAP_SECTION_COREBOOT_SIZE == bios_flash_limit + 1);
+
+ struct mem_region_device spi_boot_dev = MEM_REGION_DEV_RO_INIT(UINT32_MAX - bios_size,
+ bios_size);
+ *boot_dev = spi_boot_dev;
+}
+
+const struct region_device *boot_device_ro(void)
+{
+ /* Somehow cbfstool segfaults if this variable is in .data rather than .bss */
+ static struct mem_region_device boot_dev;
+ /* Assume a default mapping based on ROM size only. */
+ struct mem_region_device default_boot_dev = MEM_REGION_DEV_RO_INIT(rom_base, CONFIG_ROM_SIZE);
+ boot_dev = default_boot_dev;
+
+ ich_boot_device_init(&boot_dev);
+
+ return &boot_dev.rdev;
+}
+
+uint32_t spi_flash_get_mmap_windows(struct flash_mmap_window *table)
+{
+ table->flash_base = bios_flash_base;
+ table->host_base = (uint32_t)(uintptr_t)UINT32_MAX - bios_size + 1;
+ table->size = CONFIG_ROM_SIZE;
+
+ return 1;
+}

To view, visit change 79880. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: main
Gerrit-Change-Id: I5f31c175345ec3efab02255a7063054eb0ad29e4
Gerrit-Change-Number: 79880
Gerrit-PatchSet: 1
Gerrit-Owner: Arthur Heymans <arthur@aheymans.xyz>
Gerrit-MessageType: newchange