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 <kramasub@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/74606
Reviewed-by: Raul Rangel <rrangel@chromium.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Karthikeyan Ramasubramanian 2023-04-21 14:26:51 -06:00 committed by Felix Held
parent e17fc5dc0b
commit 6f1b03b8f6
4 changed files with 75 additions and 30 deletions

View File

@ -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++;
}
static int boot_dev_munmap(const struct region_device *rd __always_unused,
void *mapping __always_unused)
return mapping;
}
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;
}

View File

@ -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)

View File

@ -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 */

View File

@ -10,6 +10,7 @@
#include <commonlib/region.h>
#include <console/console.h>
#include <fmap.h>
#include <fmap_config.h>
#include <pc80/mc146818rtc.h>
#include <soc/iomap.h>
#include <soc/psp_transfer.h>
@ -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();