From 6f1b03b8f609ca4b464503f24cf2c8d606be6adc Mon Sep 17 00:00:00 2001 From: Karthikeyan Ramasubramanian Date: Fri, 21 Apr 2023 14:26:51 -0600 Subject: soc/amd/common/psp_verstage: Map/unmap boot device on need basis Currently the SPI ROM is mapped completely when the boot device is initialized. That mapping remains active throughout the execution time of PSP verstage. Every 1 MiB of mapped SPI ROM region consumes 1 TLB Slot in PSP for use during memory mapped or DMA access. With 16 MiB of mapped SPI ROM + FCH devices + 4 reserved TLB slots, 31 out of 32 total TLB slots is consumed. This leaves almost no scope for future expansion. With upcoming programs possibly using 32 MiB SPI ROM, PSP will run out of TLB slots to support 32 MiB. Hence instead of mapping the entire SPI ROM upfront, get the SPI ROM SMN address during the boot device initialization. Update the boot device region operations to map and unmap the SPI flash with the desired offset and size using the SVC call. Then anytime a memory mapped SPI ROM access is performed: map the required area, read the data and immediately unmap the area. There is no update required when using CCP DMA, since the concerned SVC call performs mapping and unmapping of the required SPI flash area implicitly. With these changes, maximum of 8 slots(size of RO section) might get used at any point in time during the PSP verstage execution. BUG=b:240664755 TEST=Build and boot to OS in Skyrim. Perform cold, warm reboots and suspend/resume cycles for 50 iterations each. Ensured that there is no impact to boot time. Change-Id: Icd44ea7b2a366e9269debcab4186d1fc71651db2 Signed-off-by: Karthikeyan Ramasubramanian Reviewed-on: https://review.coreboot.org/c/coreboot/+/74606 Reviewed-by: Raul Rangel Tested-by: build bot (Jenkins) --- src/soc/amd/common/psp_verstage/boot_dev.c | 51 ++++++++++++++++++---- src/soc/amd/common/psp_verstage/fch.c | 9 +--- .../amd/common/psp_verstage/include/psp_verstage.h | 6 ++- src/soc/amd/common/psp_verstage/psp_verstage.c | 39 ++++++++++++----- 4 files changed, 75 insertions(+), 30 deletions(-) diff --git a/src/soc/amd/common/psp_verstage/boot_dev.c b/src/soc/amd/common/psp_verstage/boot_dev.c index 4ee78b8349..c129479059 100644 --- a/src/soc/amd/common/psp_verstage/boot_dev.c +++ b/src/soc/amd/common/psp_verstage/boot_dev.c @@ -11,22 +11,51 @@ #define DEST_BUF_ALIGNMENT 16 -static void *boot_dev_mmap(const struct region_device *rd, size_t offset, - size_t size __always_unused) +static uint32_t active_map_count; + +static void *boot_dev_mmap(const struct region_device *rd, size_t offset, size_t size) { const struct mem_region_device *mdev; + void *mapping = NULL; + uint32_t ret; mdev = container_of(rd, __typeof__(*mdev), rdev); - return &(mdev->base[offset]); + if (mdev->base) { + if ((ret = svc_map_spi_rom(&mdev->base[offset], size, (void **)&mapping)) + != BL_OK) + printk(BIOS_ERR, "Failed(%d) to map SPI ROM offset: %zu, size: %zu\n", + ret, offset, size); + else + active_map_count++; + } + + return mapping; } -static int boot_dev_munmap(const struct region_device *rd __always_unused, - void *mapping __always_unused) +static int boot_dev_munmap(const struct region_device *rd, void *mapping) { + uint32_t ret; + + active_map_count--; + if ((ret = svc_unmap_spi_rom(mapping)) != BL_OK) + printk(BIOS_ERR, "Failed(%d) to unmap SPI ROM mapping %p\n", ret, mapping); return 0; } +static ssize_t boot_dev_mmap_readat(const struct region_device *rd, void *dest, + size_t offset, size_t size) +{ + void *mapping = boot_dev_mmap(rd, offset, size); + + if (!mapping) + return -1; + + memcpy(dest, mapping, size); + boot_dev_munmap(rd, mapping); + return size; +} + static ssize_t boot_dev_dma_readat(const struct region_device *rd, void *dest, size_t offset, size_t size) { @@ -38,8 +67,8 @@ static ssize_t boot_dev_dma_readat(const struct region_device *rd, void *dest, memcpy_size = size; /* Alignment requirement is only on dest buffer for CCP DMA. So do a memcpy until the destination buffer alignment requirement is met. */ - if (memcpy_size) - memcpy(dest, &(mdev->base[offset]), memcpy_size); + if (memcpy_size && boot_dev_mmap_readat(rd, dest, offset, memcpy_size) != memcpy_size) + return -1; dest = ((char *)dest + memcpy_size); offset += memcpy_size; @@ -65,8 +94,7 @@ static ssize_t boot_dev_readat(const struct region_device *rd, void *dest, if (CONFIG(PSP_VERSTAGE_CCP_DMA)) return boot_dev_dma_readat(rd, dest, offset, size); - memcpy(dest, &(mdev->base[offset]), size); - return size; + return boot_dev_mmap_readat(rd, dest, offset, size); } const struct region_device_ops boot_dev_rdev_ro_ops = { @@ -85,3 +113,8 @@ const struct region_device *boot_device_ro(void) boot_dev.base = (void *)map_spi_rom(); return &boot_dev.rdev; } + +uint32_t boot_dev_get_active_map_count(void) +{ + return active_map_count; +} diff --git a/src/soc/amd/common/psp_verstage/fch.c b/src/soc/amd/common/psp_verstage/fch.c index 7f850fd149..0517545f16 100644 --- a/src/soc/amd/common/psp_verstage/fch.c +++ b/src/soc/amd/common/psp_verstage/fch.c @@ -90,19 +90,14 @@ static struct { {"AOAC", {FCH_IO_DEVICE_AOAC}, aoac_set_bar}, }; -uintptr_t *map_spi_rom(void) +void *map_spi_rom(void) { - uintptr_t *addr = NULL; struct spirom_info spi = {0}; if (svc_get_spi_rom_info(&spi)) printk(BIOS_DEBUG, "Error getting SPI ROM info.\n"); - if (spi.SpiBiosSmnBase != 0) - if (svc_map_spi_rom(spi.SpiBiosSmnBase, CONFIG_ROM_SIZE, (void **)&addr)) - printk(BIOS_DEBUG, "Error mapping SPI ROM to address.\n"); - - return addr; + return spi.SpiBiosSmnBase; } static uint32_t map_fch_devices(void) diff --git a/src/soc/amd/common/psp_verstage/include/psp_verstage.h b/src/soc/amd/common/psp_verstage/include/psp_verstage.h index c3240fab56..6c5d4c0acf 100644 --- a/src/soc/amd/common/psp_verstage/include/psp_verstage.h +++ b/src/soc/amd/common/psp_verstage/include/psp_verstage.h @@ -38,7 +38,7 @@ #define POSTCODE_CMOS_RECOVERY 0xCA #define POSTCODE_EARLY_INIT_ERROR 0xCB #define POSTCODE_INIT_TPM_FAILED 0xCC - +#define POSTCODE_MAP_SPI_ROM_FAILED 0xCD #define POSTCODE_UNMAP_SPI_ROM 0xF0 #define POSTCODE_UNMAP_FCH_DEVICES 0xF1 @@ -57,7 +57,7 @@ void verstage_soc_aoac_init(void); void verstage_soc_espi_init(void); void verstage_soc_i2c_init(void); void verstage_soc_spi_init(void); -uintptr_t *map_spi_rom(void); +void *map_spi_rom(void); uint32_t update_psp_bios_dir(uint32_t *psp_dir_offset, uint32_t *bios_dir_offset); uint32_t save_uapp_data(void *address, uint32_t size); @@ -72,4 +72,6 @@ void report_prev_boot_status_to_vboot(void); void report_hsp_secure_state(void); +uint32_t boot_dev_get_active_map_count(void); + #endif /* PSP_VERSTAGE_H */ diff --git a/src/soc/amd/common/psp_verstage/psp_verstage.c b/src/soc/amd/common/psp_verstage/psp_verstage.c index e5b0277ba9..dfea43d6c9 100644 --- a/src/soc/amd/common/psp_verstage/psp_verstage.c +++ b/src/soc/amd/common/psp_verstage/psp_verstage.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -74,7 +75,8 @@ static uint32_t update_boot_region(struct vb2_context *ctx) const char *fname; const char *hash_fname; void *amdfw_location; - void *boot_dev_base = rdev_mmap_full(boot_device_ro()); + void *map_base = NULL; + size_t map_offset; /* Continue booting from RO */ if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE) { @@ -85,36 +87,53 @@ static uint32_t update_boot_region(struct vb2_context *ctx) if (vboot_is_firmware_slot_a(ctx)) { fname = "apu/amdfw_a"; hash_fname = "apu/amdfw_a_hash"; + map_offset = FMAP_SECTION_FW_MAIN_A_START - FMAP_SECTION_FLASH_START; + map_base = rdev_mmap(boot_device_ro(), map_offset, FMAP_SECTION_FW_MAIN_A_SIZE); } else { fname = "apu/amdfw_b"; hash_fname = "apu/amdfw_b_hash"; + map_offset = FMAP_SECTION_FW_MAIN_B_START - FMAP_SECTION_FLASH_START; + map_base = rdev_mmap(boot_device_ro(), map_offset, FMAP_SECTION_FW_MAIN_B_SIZE); + } + + if (!map_base) { + printk(BIOS_ERR, "Failed to map RW FW_MAIN section.\n"); + return POSTCODE_MAP_SPI_ROM_FAILED; } amdfw_location = cbfs_map(fname, NULL); if (!amdfw_location) { printk(BIOS_ERR, "AMD Firmware table not found.\n"); + rdev_munmap(boot_device_ro(), map_base); return POSTCODE_AMD_FW_MISSING; } + ef_table = (struct embedded_firmware *)amdfw_location; if (ef_table->signature != EMBEDDED_FW_SIGNATURE) { printk(BIOS_ERR, "ROMSIG address is not correct.\n"); + cbfs_unmap(amdfw_location); + rdev_munmap(boot_device_ro(), map_base); return POSTCODE_ROMSIG_MISMATCH_ERROR; } psp_dir_addr = ef_table->new_psp_directory; bios_dir_addr = get_bios_dir_addr(ef_table); psp_dir_in_spi = (uint32_t *)((psp_dir_addr & SPI_ADDR_MASK) + - (uint32_t)boot_dev_base); + (uint32_t)map_base - map_offset); if (*psp_dir_in_spi != PSP_COOKIE) { printk(BIOS_ERR, "PSP Directory address is not correct.\n"); + cbfs_unmap(amdfw_location); + rdev_munmap(boot_device_ro(), map_base); return POSTCODE_PSP_COOKIE_MISMATCH_ERROR; } if (bios_dir_addr) { bios_dir_in_spi = (uint32_t *)((bios_dir_addr & SPI_ADDR_MASK) + - (uint32_t)boot_dev_base); + (uint32_t)map_base - map_offset); if (*bios_dir_in_spi != BHD_COOKIE) { printk(BIOS_ERR, "BIOS Directory address is not correct.\n"); + cbfs_unmap(amdfw_location); + rdev_munmap(boot_device_ro(), map_base); return POSTCODE_BHD_COOKIE_MISMATCH_ERROR; } } @@ -128,12 +147,16 @@ static uint32_t update_boot_region(struct vb2_context *ctx) if (update_psp_bios_dir(&psp_dir_addr, &bios_dir_addr)) { printk(BIOS_ERR, "Updated BIOS Directory could not be set.\n"); + cbfs_unmap(amdfw_location); + rdev_munmap(boot_device_ro(), map_base); return POSTCODE_UPDATE_PSP_BIOS_DIR_ERROR; } if (CONFIG(SEPARATE_SIGNED_PSPFW)) update_psp_fw_hash_table(hash_fname); + cbfs_unmap(amdfw_location); + rdev_munmap(boot_device_ro(), map_base); return 0; } @@ -208,7 +231,6 @@ void Main(void) { uint32_t retval; struct vb2_context *ctx = NULL; - void *boot_dev_base; uint32_t bootmode; /* @@ -324,14 +346,7 @@ void Main(void) if (retval) reboot_into_recovery(ctx, retval); - - post_code(POSTCODE_UNMAP_SPI_ROM); - boot_dev_base = rdev_mmap_full(boot_device_ro()); - if (boot_dev_base) { - if (svc_unmap_spi_rom((void *)boot_dev_base)) - printk(BIOS_ERR, "Error unmapping SPI rom\n"); - } - + assert(!boot_dev_get_active_map_count()); post_code(POSTCODE_UNMAP_FCH_DEVICES); unmap_fch_devices(); -- cgit v1.2.3