soc/amd/picasso: add psp_verstage

This is the main code for building coreboot's verstage as a userspace
application to run on the PSP.  It does a minimal setup of hardware,
then runs verstage_main.  It uses hardware hashing to increase the speed
and will directly reboot into recovery mode if there are any failures.

BUG=b:158124527
TEST=Build & boot trembyle

Signed-off-by: Martin Roth <martin@coreboot.org>
Change-Id: Ia58839caa5bfbae0408702ee8d02ef482f2861c4
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41816
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Raul Rangel <rrangel@chromium.org>
This commit is contained in:
Martin Roth 2020-05-28 00:44:50 -06:00 committed by Martin Roth
parent ac41f58235
commit c7acf1666a
22 changed files with 1125 additions and 107 deletions

View File

@ -10,7 +10,7 @@ if SOC_AMD_PICASSO
config CPU_SPECIFIC_OPTIONS
def_bool y
select ARCH_BOOTBLOCK_X86_32
select ARCH_VERSTAGE_X86_32
select ARCH_VERSTAGE_X86_32 if !VBOOT_STARTS_BEFORE_BOOTBLOCK
select ARCH_ROMSTAGE_X86_32
select ARCH_RAMSTAGE_X86_32
select RESET_VECTOR_IN_RAM
@ -473,6 +473,16 @@ config PSP_BOOTLOADER_FILE
Note that this option may conflict with the whitelist file if a
different PSP bootloader binary is specified.
config PSP_SHAREDMEM_SIZE
hex "Maximum size of shared memory area"
default 0x3000 if VBOOT
default 0x0
help
Sets the maximum size for the PSP to pass the vboot workbuf and
any logs or timestamps back to coreboot. This will be copied
into main memory by the PSP and will be available when the x86 is
started.
config PSP_UNLOCK_SECURE_DEBUG
bool "Unlock secure debug"
default n
@ -481,4 +491,17 @@ config PSP_UNLOCK_SECURE_DEBUG
endmenu
config VBOOT
select VBOOT_VBNV_CMOS
select VBOOT_VBNV_CMOS_BACKUP_TO_FLASH if ! VBOOT_STARTS_BEFORE_BOOTBLOCK
config VBOOT_STARTS_BEFORE_BOOTBLOCK
def_bool n
depends on VBOOT
select ARCH_VERSTAGE_ARMV7
help
Runs verstage on the PSP. Only available on
certain Chrome OS branded parts from AMD.
endif # SOC_AMD_PICASSO

View File

@ -9,6 +9,7 @@ subdirs-y += ../../../cpu/x86/cache
subdirs-y += ../../../cpu/x86/mtrr
subdirs-y += ../../../cpu/x86/pae
subdirs-y += ../../../cpu/x86/smm
subdirs-$(CONFIG_VBOOT_STARTS_BEFORE_BOOTBLOCK) += psp_verstage
bootblock-y += bootblock/pre_c.S
bootblock-y += bootblock/bootblock.c
@ -21,11 +22,13 @@ bootblock-y += tsc_freq.c
bootblock-y += gpio.c
bootblock-y += smi_util.c
bootblock-y += config.c
bootblock-y += ../../../arch/x86/memmove.c
romstage-y += i2c.c
romstage-y += romstage.c
romstage-y += gpio.c
romstage-y += pmutil.c
romstage-y += reset.c
romstage-y += memmap.c
romstage-y += uart.c
romstage-$(CONFIG_PICASSO_CONSOLE_UART) += uart_console.c
@ -37,14 +40,15 @@ romstage-y += psp.c
romstage-y += config.c
romstage-y += mrc_cache.c
verstage-y += gpio.c
verstage-y += i2c.c
verstage-y += pmutil.c
verstage-y += config.c
verstage-y += aoac.c
verstage-y += uart.c
verstage-$(CONFIG_PICASSO_CONSOLE_UART) += uart_console.c
verstage-y += tsc_freq.c
verstage_x86-y += gpio.c
verstage_x86-y += uart.c
verstage_x86-$(CONFIG_PICASSO_CONSOLE_UART) += uart_console.c
verstage_x86-y += tsc_freq.c
verstage_x86-y += reset.c
ramstage-y += i2c.c
ramstage-y += chip.c
@ -58,6 +62,7 @@ ramstage-y += gpio.c
ramstage-y += aoac.c
ramstage-y += southbridge.c
ramstage-y += pmutil.c
ramstage-y += reset.c
ramstage-y += acp.c
ramstage-y += sata.c
ramstage-y += memmap.c
@ -75,8 +80,6 @@ ramstage-y += config.c
ramstage-y += update_microcode.c
ramstage-y += graphics.c
all-y += reset.c
smm-y += smihandler.c
smm-y += smi_util.c
smm-y += tsc_freq.c

View File

@ -12,7 +12,7 @@
#include <soc/iomap.h>
#include <soc/southbridge.h>
#include <acpi/acpi_device.h>
#include <arch/smp/mpspec.h>
#include <arch/x86/include/arch/smp/mpspec.h> /* point from top level */
/*
USB 2.0 PHY Parameters

View File

@ -1,101 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <memlayout.h>
#include <arch/header.ld>
#define EARLY_RESERVED_DRAM_START(addr) SYMBOL(early_reserved_dram, addr)
#define EARLY_RESERVED_DRAM_END(addr) SYMBOL(eearly_reserved_dram, addr)
#define PSP_SHAREDMEM_DRAM_START(addr) SYMBOL(psp_sharedmem_dram, addr)
#define PSP_SHAREDMEM_DRAM_END(addr) SYMBOL(epsp_sharedmem_dram, addr)
/*
*
* +--------------------------------+
* | |
* | |
* | |
* | |
* | |
* | |
* | |
* reserved_dram_end +--------------------------------+
* | |
* | verstage (if reqd) |
* | (VERSTAGE_SIZE) |
* +--------------------------------+ VERSTAGE_ADDR
* | |
* | FSP-M |
* | (FSP_M_SIZE) |
* +--------------------------------+ FSP_M_ADDR
* | |X86_RESET_VECTOR = ROMSTAGE_ADDR + ROMSTAGE_SIZE - 0x10
* | romstage |
* | (ROMSTAGE_SIZE) |
* +--------------------------------+ ROMSTAGE_ADDR
* | bootblock |
* | (C_ENV_BOOTBLOCK_SIZE) |
* +--------------------------------+ BOOTBLOCK_ADDR
* | Unused hole |
* +--------------------------------+
* | FMAP cache (FMAP_SIZE) |
* +--------------------------------+ PSP_SHAREDMEM_BASE + PSP_SHAREDMEM_SIZE + PRERAM_CBMEM_CONSOLE_SIZE + 0x200
* | Early Timestamp region (512B) |
* +--------------------------------+ PSP_SHAREDMEM_BASE + PSP_SHAREDMEM_SIZE + PRERAM_CBMEM_CONSOLE_SIZE
* | Preram CBMEM console |
* | (PRERAM_CBMEM_CONSOLE_SIZE) |
* +--------------------------------+ PSP_SHAREDMEM_BASE + PSP_SHAREDMEM_SIZE
* | PSP shared (vboot workbuf) |
* | (PSP_SHAREDMEM_SIZE) |
* +--------------------------------+ PSP_SHAREDMEM_BASE
* | APOB (64KiB) |
* +--------------------------------+ PSP_APOB_DRAM_ADDRESS
* | Early BSP stack |
* | (EARLYRAM_BSP_STACK_SIZE) |
* reserved_dram_start +--------------------------------+ EARLY_RESERVED_DRAM_BASE
* | DRAM |
* +--------------------------------+ 0x100000
* | Option ROM |
* +--------------------------------+ 0xc0000
* | Legacy VGA |
* +--------------------------------+ 0xa0000
* | DRAM |
* +--------------------------------+ 0x0
*/
SECTIONS
{
DRAM_START(0x0)
EARLY_RESERVED_DRAM_START(CONFIG_EARLY_RESERVED_DRAM_BASE)
EARLYRAM_STACK(., CONFIG_EARLYRAM_BSP_STACK_SIZE)
REGION(apob, CONFIG_PSP_APOB_DRAM_ADDRESS, 64K, 1)
#if CONFIG(VBOOT)
PSP_SHAREDMEM_DRAM_START(CONFIG_PSP_SHAREDMEM_BASE)
VBOOT2_WORK(., VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE)
PSP_SHAREDMEM_DRAM_END(CONFIG_PSP_SHAREDMEM_BASE + CONFIG_PSP_SHAREDMEM_SIZE)
#endif
PRERAM_CBMEM_CONSOLE(., CONFIG_PRERAM_CBMEM_CONSOLE_SIZE)
TIMESTAMP(., 0x200)
FMAP_CACHE(., FMAP_SIZE)
_ = ASSERT((CONFIG_BOOTBLOCK_ADDR + CONFIG_C_ENV_BOOTBLOCK_SIZE - 0x10) == CONFIG_X86_RESET_VECTOR, "Reset vector should be -0x10 from end of bootblock");
_ = ASSERT(CONFIG_BOOTBLOCK_ADDR == ((CONFIG_BOOTBLOCK_ADDR + 0xFFFF) & 0xFFFF0000), "Bootblock must be 16 bit aligned");
BOOTBLOCK(CONFIG_BOOTBLOCK_ADDR, CONFIG_C_ENV_BOOTBLOCK_SIZE)
ROMSTAGE(CONFIG_ROMSTAGE_ADDR, CONFIG_ROMSTAGE_SIZE)
REGION(fspm, CONFIG_FSP_M_ADDR, CONFIG_FSP_M_SIZE, 1)
#if CONFIG(VBOOT_SEPARATE_VERSTAGE)
VERSTAGE(CONFIG_VERSTAGE_ADDR, CONFIG_VERSTAGE_SIZE)
#endif
EARLY_RESERVED_DRAM_END(.)
RAMSTAGE(CONFIG_RAMBASE, 8M)
}
#if ENV_BOOTBLOCK
/* Bootblock specific scripts which provide more SECTION directives. */
#include <cpu/x86/16bit/entry16.ld>
#include <cpu/x86/16bit/reset16.ld>
#endif /* ENV_BOOTBLOCK */
#if ENV_SEPARATE_VERSTAGE && CONFIG(VBOOT_STARTS_BEFORE_BOOTBLOCK)
#include "memlayout_psp_verstage.ld"
#else
#include "memlayout_x86.ld"
#endif /* ENV_SEPARATE_VERSTAGE && CONFIG(VBOOT_STARTS_BEFORE_BOOTBLOCK) */

View File

@ -0,0 +1,65 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <memlayout.h>
/*
* Start of available space is 0x15000 and this is where the
* header for the user app (verstage) must be mapped.
* Size is 0x28000 bytes
*/
#define PSP_SRAM_START 0x15000
#define PSP_SRAM_SIZE 160K
#define VERSTAGE_START 0x15000
#define VERSTAGE_SIZE 60K
#define VBOOT_WORK_START VERSTAGE_START + VERSTAGE_SIZE
#define VBOOT_WORK_SIZE 12K
#define FMAP_CACHE_SIZE 2K
/*
* The temp stack can be made much smaller if needed - even 256 bytes
* should be sufficient. This is just for the function mapping the
* actual stack.
*/
#define PSP_VERSTAGE_TEMP_STACK_START 0x39000
#define PSP_VERSTAGE_TEMP_STACK_SIZE 4K
/*
* The top of the stack must be 4k aligned, so set the bottom as 4k aligned
* and make the size a multiple of 4k
*/
#define PSP_VERSTAGE_STACK_START 0x3B000
#define PSP_VERSTAGE_STACK_SIZE 8K
ENTRY(_psp_vs_start)
SECTIONS
{
SRAM_START(PSP_SRAM_START)
_verstage = .;
.text : { *(PSP_HEADER_DATA) }
.text : { *(.text._psp_vs_start) }
.text : { *(.text.Main) }
.text : { *(.text*) }
.rodata : { *(.rodata*) }
.data : { *(.data*) }
.data : { *(PSP_FOOTER_DATA) }
_bss_start = .;
.bss : { *(.bss*) }
_bss_end = .;
_everstage = _verstage + VERSTAGE_SIZE;
REGION(vboot2_work, VBOOT_WORK_START, VBOOT_WORK_SIZE, 64)
FMAP_CACHE(., FMAP_SIZE)
PSP_VERSTAGE_TEMP_STACK_END = (PSP_VERSTAGE_TEMP_STACK_START + PSP_VERSTAGE_TEMP_STACK_SIZE );
REGION(stack, PSP_VERSTAGE_STACK_START, PSP_VERSTAGE_STACK_SIZE, 64)
PSP_VERSTAGE_STACK_BASE = _stack;
PSP_VERSTAGE_STACK_END = _estack;
SRAM_END(PSP_SRAM_START + PSP_SRAM_SIZE)
}

View File

@ -0,0 +1,101 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <memlayout.h>
#include <arch/header.ld>
#define EARLY_RESERVED_DRAM_START(addr) SYMBOL(early_reserved_dram, addr)
#define EARLY_RESERVED_DRAM_END(addr) SYMBOL(eearly_reserved_dram, addr)
#define PSP_SHAREDMEM_DRAM_START(addr) SYMBOL(psp_sharedmem_dram, addr)
#define PSP_SHAREDMEM_DRAM_END(addr) SYMBOL(epsp_sharedmem_dram, addr)
/*
*
* +--------------------------------+
* | |
* | |
* | |
* | |
* | |
* | |
* | |
* reserved_dram_end +--------------------------------+
* | |
* | verstage (if reqd) |
* | (VERSTAGE_SIZE) |
* +--------------------------------+ VERSTAGE_ADDR
* | |
* | FSP-M |
* | (FSP_M_SIZE) |
* +--------------------------------+ FSP_M_ADDR
* | |X86_RESET_VECTOR = ROMSTAGE_ADDR + ROMSTAGE_SIZE - 0x10
* | romstage |
* | (ROMSTAGE_SIZE) |
* +--------------------------------+ ROMSTAGE_ADDR
* | bootblock |
* | (C_ENV_BOOTBLOCK_SIZE) |
* +--------------------------------+ BOOTBLOCK_ADDR
* | Unused hole |
* +--------------------------------+
* | FMAP cache (FMAP_SIZE) |
* +--------------------------------+ PSP_SHAREDMEM_BASE + PSP_SHAREDMEM_SIZE + PRERAM_CBMEM_CONSOLE_SIZE + 0x200
* | Early Timestamp region (512B) |
* +--------------------------------+ PSP_SHAREDMEM_BASE + PSP_SHAREDMEM_SIZE + PRERAM_CBMEM_CONSOLE_SIZE
* | Preram CBMEM console |
* | (PRERAM_CBMEM_CONSOLE_SIZE) |
* +--------------------------------+ PSP_SHAREDMEM_BASE + PSP_SHAREDMEM_SIZE
* | PSP shared (vboot workbuf) |
* | (PSP_SHAREDMEM_SIZE) |
* +--------------------------------+ PSP_SHAREDMEM_BASE
* | APOB (64KiB) |
* +--------------------------------+ PSP_APOB_DRAM_ADDRESS
* | Early BSP stack |
* | (EARLYRAM_BSP_STACK_SIZE) |
* reserved_dram_start +--------------------------------+ EARLY_RESERVED_DRAM_BASE
* | DRAM |
* +--------------------------------+ 0x100000
* | Option ROM |
* +--------------------------------+ 0xc0000
* | Legacy VGA |
* +--------------------------------+ 0xa0000
* | DRAM |
* +--------------------------------+ 0x0
*/
SECTIONS
{
DRAM_START(0x0)
EARLY_RESERVED_DRAM_START(CONFIG_EARLY_RESERVED_DRAM_BASE)
EARLYRAM_STACK(., CONFIG_EARLYRAM_BSP_STACK_SIZE)
REGION(apob, CONFIG_PSP_APOB_DRAM_ADDRESS, 64K, 1)
#if CONFIG(VBOOT)
PSP_SHAREDMEM_DRAM_START(CONFIG_PSP_SHAREDMEM_BASE)
VBOOT2_WORK(., VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE)
PSP_SHAREDMEM_DRAM_END(CONFIG_PSP_SHAREDMEM_BASE + CONFIG_PSP_SHAREDMEM_SIZE)
#endif
PRERAM_CBMEM_CONSOLE(., CONFIG_PRERAM_CBMEM_CONSOLE_SIZE)
TIMESTAMP(., 0x200)
FMAP_CACHE(., FMAP_SIZE)
_ = ASSERT((CONFIG_BOOTBLOCK_ADDR + CONFIG_C_ENV_BOOTBLOCK_SIZE - 0x10) == CONFIG_X86_RESET_VECTOR, "Reset vector should be -0x10 from end of bootblock");
_ = ASSERT(CONFIG_BOOTBLOCK_ADDR == ((CONFIG_BOOTBLOCK_ADDR + 0xFFFF) & 0xFFFF0000), "Bootblock must be 16 bit aligned");
BOOTBLOCK(CONFIG_BOOTBLOCK_ADDR, CONFIG_C_ENV_BOOTBLOCK_SIZE)
ROMSTAGE(CONFIG_ROMSTAGE_ADDR, CONFIG_ROMSTAGE_SIZE)
REGION(fspm, CONFIG_FSP_M_ADDR, CONFIG_FSP_M_SIZE, 1)
#if CONFIG(VBOOT_SEPARATE_VERSTAGE)
VERSTAGE(CONFIG_VERSTAGE_ADDR, CONFIG_VERSTAGE_SIZE)
#endif
EARLY_RESERVED_DRAM_END(.)
RAMSTAGE(CONFIG_RAMBASE, 8M)
}
#if ENV_BOOTBLOCK
/* Bootblock specific scripts which provide more SECTION directives. */
#include <cpu/x86/16bit/entry16.ld>
#include <cpu/x86/16bit/reset16.ld>
#endif /* ENV_BOOTBLOCK */

View File

@ -0,0 +1,24 @@
# SPDX-License-Identifier: GPL-2.0-only
verstage-generic-ccopts += -I$(src)/soc/amd/picasso/psp_verstage/include
verstage-generic-ccopts += -I$(src)/vendorcode/amd/fsp/picasso/include
CPPFLAGS_common += -I$(VBOOT_SOURCE)/firmware/2lib/include/
verstage-y += delay.c
verstage-y += fch.c
verstage-y += pmutil.c
verstage-y += post.c
verstage-y += printk.c
verstage-y += psp_verstage.c
verstage-y += psp.c
verstage-y += reset.c
verstage-y += svc.c
verstage-y += timer.c
verstage-y += timestamp.c
verstage-y += vboot_crypto.c
verstage-y += $(top)/src/vendorcode/amd/fsp/picasso/bl_uapp/bl_uapp_startup.S
verstage-y += $(top)/src/vendorcode/amd/fsp/picasso/bl_uapp/bl_uapp_end.S
$(obj)/psp_verstage.bin: $(objcbfs)/verstage.elf
$(OBJCOPY_verstage) -O binary $^ $@

View File

@ -0,0 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <bl_uapp/bl_syscall_public.h>
#include <delay.h>
#include <stdint.h>
void udelay(uint32_t usecs)
{
svc_delay_in_usec(usecs);
}

View File

@ -0,0 +1,159 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include "psp_verstage.h"
#include <amdblocks/acpimmio.h>
#include <amdblocks/espi.h>
#include <arch/exception.h>
#include <arch/hlt.h>
#include <arch/io.h>
#include <bl_uapp/bl_errorcodes_public.h>
#include <bl_uapp/bl_syscall_public.h>
#include <console/console.h>
#include <delay.h>
#include <soc/i2c.h>
#include <soc/southbridge.h>
#include <stdint.h>
#include <timestamp.h>
static void i2c3_set_bar(void *bar)
{
i2c_set_bar(3, (uintptr_t)bar);
}
static void i2c2_set_bar(void *bar)
{
i2c_set_bar(2, (uintptr_t)bar);
}
static void espi_set_bar(void *bar)
{
espi_update_static_bar((uintptr_t)bar);
}
static void iomux_set_bar(void *bar)
{
acpimmio_iomux = bar;
}
static void misc_set_bar(void *bar)
{
acpimmio_misc = bar;
}
static void gpio_set_bar(void *bar)
{
acpimmio_gpio0 = bar;
}
static uintptr_t io_bar;
static void io_set_bar(void *bar)
{
io_bar = (uintptr_t)bar;
}
u8 io_read8(u16 reg)
{
return read8((void *)(io_bar + reg));
}
void io_write8(u16 reg, u8 value)
{
write8((void *)(io_bar + reg), value);
}
static struct {
const char *name;
struct {
FCH_IO_DEVICE device;
uint32_t arg0;
} args;
void (*set_bar)(void *bar);
void *_bar;
} bar_map[] = {
{"IOMUX", {FCH_IO_DEVICE_IOMUX}, iomux_set_bar},
{"MISC", {FCH_IO_DEVICE_MISC}, misc_set_bar},
{"GPIO", {FCH_IO_DEVICE_GPIO}, gpio_set_bar},
{"IO", {FCH_IO_DEVICE_IOPORT}, io_set_bar},
{"eSPI", {FCH_IO_DEVICE_ESPI}, espi_set_bar},
{"I2C2", {FCH_IO_DEVICE_I2C, 2}, i2c2_set_bar},
{"I2C3", {FCH_IO_DEVICE_I2C, 3}, i2c3_set_bar},
};
uintptr_t *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;
}
void sb_enable_legacy_io(void)
{
pm_io_write32(PM_DECODE_EN, pm_io_read32(PM_DECODE_EN) | LEGACY_IO_EN);
}
static uint32_t map_fch_devices(void)
{
void *bar;
uint32_t err;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(bar_map); ++i) {
err = svc_map_fch_dev(bar_map[i].args.device, bar_map[i].args.arg0, 0, &bar);
if (err) {
printk(BIOS_ERR, "Failed to map %s: %u\n", bar_map[i].name, err);
return err;
}
bar_map[i]._bar = bar;
bar_map[i].set_bar(bar);
}
return BL_UAPP_OK;
}
uint32_t unmap_fch_devices(void)
{
void *bar;
uint32_t err, rtn = BL_UAPP_OK;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(bar_map); ++i) {
bar = bar_map[i]._bar;
if (!bar)
continue;
err = svc_unmap_fch_dev(bar_map[i].args.device, bar);
if (err) {
printk(BIOS_ERR, "Failed to unmap %s: %u\n", bar_map[i].name, err);
rtn = err;
} else {
bar_map[i]._bar = NULL;
bar_map[i].set_bar(NULL);
}
}
return rtn;
}
uint32_t verstage_soc_early_init(void)
{
return map_fch_devices();
}
void verstage_soc_init(void)
{
if (CONFIG(SOC_AMD_COMMON_BLOCK_USE_ESPI)) {
espi_setup();
espi_configure_decodes();
}
}

View File

@ -0,0 +1,21 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef __ARCH_IO_H__
#define __ARCH_IO_H__
#include <stdint.h>
u8 io_read8(u16 reg);
void io_write8(u16 reg, u8 value);
static inline void outb(uint8_t value, uint16_t port)
{
io_write8(port, value);
}
static inline uint8_t inb(uint16_t port)
{
return io_read8(port);
}
#endif

View File

@ -0,0 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <bl_uapp/bl_syscall_public.h>
#include <bootmode.h>
#include <console/console.h>
#include <stdint.h>
int platform_is_resuming(void)
{
uint32_t bootmode = 0;
if (svc_get_boot_mode(&bootmode)) {
printk(BIOS_ERR, "Error getting boot mode. Assuming no resume.\n");
return 0;
}
if (bootmode == PSP_BOOT_MODE_S3_RESUME || bootmode == PSP_BOOT_MODE_S0i3_RESUME)
return 1;
return 0;
}

View File

@ -0,0 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <bl_uapp/bl_syscall_public.h>
#include <console/console.h>
#include <post.h>
void arch_post_code(u8 value)
{
if (CONFIG(POST_IO) && CONFIG_POST_IO_PORT == 0x80)
svc_write_postcode(value);
}

View File

@ -0,0 +1,38 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <bl_uapp/bl_syscall_public.h>
#include <console/console.h>
#include <console/streams.h>
#include <stdarg.h>
#include <stdint.h>
void console_hw_init(void)
{
// Nothing to init for svc_debug_print
}
int do_printk(int msg_level, const char *fmt, ...)
{
va_list args;
int i;
va_start(args, fmt);
i = do_vprintk(msg_level, fmt, args);
va_end(args);
return i;
}
int do_vprintk(int msg_level, const char *fmt, va_list args)
{
int i, log_this;
char buf[256];
log_this = console_log_level(msg_level);
if (log_this < CONSOLE_LOG_FAST)
return 0;
i = vsnprintf(buf, sizeof(buf), fmt, args);
svc_debug_print(buf);
return i;
}

View File

@ -0,0 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <smp/node.h>
int boot_cpu(void)
{
return 1;
}

View File

@ -0,0 +1,216 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include "psp_verstage.h"
#include <bl_uapp/bl_syscall_public.h>
#include <boot_device.h>
#include <console/console.h>
#include <security/vboot/misc.h>
#include <security/vboot/symbols.h>
#include <security/vboot/vboot_common.h>
#include <arch/stages.h>
#include <stdarg.h>
#include <stdio.h>
#define RUN_PSP_SVC_TESTS 0
extern char _bss_start, _bss_end;
static struct mem_region_device boot_dev =
MEM_REGION_DEV_RO_INIT(NULL, CONFIG_ROM_SIZE);
void __weak verstage_mainboard_early_init(void) {}
void __weak verstage_mainboard_init(void) {}
static void reboot_into_recovery(struct vb2_context *ctx, uint32_t subcode)
{
subcode += PSP_VBOOT_ERROR_SUBCODE;
svc_write_postcode(subcode);
vb2api_fail(ctx, VB2_RECOVERY_RO_UNSPECIFIED, (int)subcode);
vboot_save_data(ctx);
svc_debug_print("Rebooting into recovery\n");
vboot_reboot();
}
/*
* Tell the PSP where to load the rest of the firmware from
*/
static uint32_t update_boot_region(struct vb2_context *ctx)
{
struct psp_ef_table *ef_table;
uint32_t psp_dir_addr, bios_dir_addr;
uint32_t *psp_dir_in_spi, *bios_dir_in_spi;
/* Continue booting from RO */
if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE) {
printk(BIOS_ERR, "In recovery mode. Staying in RO.\n");
return 0;
}
if (vboot_is_firmware_slot_a(ctx)) {
printk(BIOS_SPEW, "Using FMAP RW_A region.\n");
ef_table = (struct psp_ef_table *)((CONFIG_PICASSO_FW_A_POSITION &
SPI_ADDR_MASK) + (uint32_t)boot_dev.base);
} else {
printk(BIOS_SPEW, "Using FMAP RW_B region.\n");
ef_table = (struct psp_ef_table *)((CONFIG_PICASSO_FW_B_POSITION &
SPI_ADDR_MASK) + (uint32_t)boot_dev.base);
}
if (ef_table->signature != EMBEDDED_FW_SIGNATURE) {
printk(BIOS_ERR, "Error: ROMSIG address is not correct.\n");
return POSTCODE_ROMSIG_MISMATCH_ERROR;
}
psp_dir_addr = ef_table->psp_table;
bios_dir_addr = ef_table->bios1_entry;
psp_dir_in_spi = (uint32_t *)((psp_dir_addr & SPI_ADDR_MASK) +
(uint32_t)boot_dev.base);
bios_dir_in_spi = (uint32_t *)((bios_dir_addr & SPI_ADDR_MASK) +
(uint32_t)boot_dev.base);
if (*psp_dir_in_spi != PSP_COOKIE) {
printk(BIOS_ERR, "Error: PSP Directory address is not correct.\n");
return POSTCODE_PSP_COOKIE_MISMATCH_ERROR;
}
if (*bios_dir_in_spi != BDT1_COOKIE) {
printk(BIOS_ERR, "Error: BIOS Directory address is not correct.\n");
return POSTCODE_BDT1_COOKIE_MISMATCH_ERROR;
}
if (svc_update_psp_bios_dir((void *)&psp_dir_addr,
(void *)&bios_dir_addr, DIR_OFFSET_SET)) {
printk(BIOS_ERR, "Error: Updated BIOS Directory could not be set.\n");
return POSTCODE_UPDATE_PSP_BIOS_DIR_ERROR;
}
return 0;
}
/*
* Save workbuf (and soon memory console and timestamps) to the bootloader to pass
* back to coreboot.
*/
static uint32_t save_buffers(struct vb2_context **ctx)
{
uint32_t retval;
uint32_t buffer_size = DEFAULT_WORKBUF_TRANSFER_SIZE;
uint32_t max_buffer_size;
/*
* This should never fail, but if it does, we should still try to
* save the buffer. If that fails, then we should go to recovery mode.
*/
if (svc_get_max_workbuf_size(&max_buffer_size)) {
post_code(POSTCODE_DEFAULT_BUFFER_SIZE_NOTICE);
printk(BIOS_NOTICE, "Notice: using default transfer buffer size.\n");
max_buffer_size = DEFAULT_WORKBUF_TRANSFER_SIZE;
}
printk(BIOS_DEBUG, "\nMaximum buffer size: %d bytes\n", max_buffer_size);
retval = vb2api_relocate(_vboot2_work, _vboot2_work, buffer_size, ctx);
if (retval != VB2_SUCCESS) {
printk(BIOS_ERR, "Error shrinking workbuf. Error code %#x\n", retval);
buffer_size = VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE;
post_code(POSTCODE_WORKBUF_RESIZE_WARNING);
}
if (buffer_size > max_buffer_size) {
printk(BIOS_ERR, "Error: Workbuf is larger than max buffer size.\n");
post_code(POSTCODE_WORKBUF_BUFFER_SIZE_ERROR);
return POSTCODE_WORKBUF_BUFFER_SIZE_ERROR;
}
retval = svc_save_uapp_data(UAPP_COPYBUF_CHROME_WORKBUF, (void *)_vboot2_work,
buffer_size);
if (retval) {
printk(BIOS_ERR, "Error: Could not save workbuf. Error code 0x%08x\n",
retval);
return POSTCODE_WORKBUF_SAVE_ERROR;
}
return 0;
}
void Main(void)
{
uint32_t retval;
struct vb2_context *ctx = NULL;
/*
* Do not use printk() before console_init()
* Do not use post_code() before verstage_mainboard_init()
*/
svc_write_postcode(POSTCODE_ENTERED_PSP_VERSTAGE);
svc_debug_print("Entering verstage on PSP\n");
memset(&_bss_start, '\0', &_bss_end - &_bss_start);
svc_write_postcode(POSTCODE_CONSOLE_INIT);
console_init();
svc_write_postcode(POSTCODE_EARLY_INIT);
retval = verstage_soc_early_init();
if (retval) {
svc_debug_print("verstage_soc_early_init failed\n");
reboot_into_recovery(NULL, retval);
}
svc_debug_print("calling verstage_mainboard_early_init\n");
verstage_mainboard_early_init();
svc_write_postcode(POSTCODE_LATE_INIT);
sb_enable_legacy_io();
verstage_soc_init();
verstage_mainboard_init();
post_code(POSTCODE_VERSTAGE_MAIN);
verstage_main();
post_code(POSTCODE_SAVE_BUFFERS);
retval = save_buffers(&ctx);
if (retval)
goto err;
post_code(POSTCODE_UPDATE_BOOT_REGION);
retval = update_boot_region(ctx);
if (retval)
goto err;
post_code(POSTCODE_UNMAP_SPI_ROM);
if (boot_dev.base) {
if (svc_unmap_spi_rom((void *)boot_dev.base))
printk(BIOS_ERR, "Error unmapping SPI rom\n");
}
post_code(POSTCODE_UNMAP_FCH_DEVICES);
unmap_fch_devices();
post_code(POSTCODE_LEAVING_VERSTAGE);
printk(BIOS_DEBUG, "Leaving verstage on PSP\n");
svc_exit(retval);
err:
reboot_into_recovery(ctx, retval);
}
const struct region_device *boot_device_ro(void)
{
uintptr_t *addr;
addr = map_spi_rom();
mem_region_device_ro_init(&boot_dev, (void *)addr, CONFIG_ROM_SIZE);
return &boot_dev.rdev;
}
/*
* The stage_entry function is not used directly, but stage_entry() is marked as an entry
* point in arm/arch/header.h, so if stage_entry() isn't present and calling Main(), all
* the verstage code gets dropped by the linker. Slightly hacky, but mostly harmless.
*/
void stage_entry(uintptr_t stage_arg)
{
Main();
}

View File

@ -0,0 +1,55 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef PSP_VERSTAGE_H
#define PSP_VERSTAGE_H
#include <stdint.h>
#define EMBEDDED_FW_SIGNATURE 0x55aa55aa
#define PSP_COOKIE 0x50535024 /* 'PSP$' */
#define BDT1_COOKIE 0x44484224 /* 'DHB$ */
#define PSP_VBOOT_ERROR_SUBCODE 0x0D5D0000
#define POSTCODE_ENTERED_PSP_VERSTAGE 0x00
#define POSTCODE_CONSOLE_INIT 0x01
#define POSTCODE_EARLY_INIT 0x02
#define POSTCODE_LATE_INIT 0x03
#define POSTCODE_VERSTAGE_MAIN 0x04
#define POSTCODE_SAVE_BUFFERS 0x0F
#define POSTCODE_UPDATE_BOOT_REGION 0x0F
#define POSTCODE_DEFAULT_BUFFER_SIZE_NOTICE 0xC0
#define POSTCODE_WORKBUF_RESIZE_WARNING 0xC1
#define POSTCODE_WORKBUF_SAVE_ERROR 0xC2
#define POSTCODE_WORKBUF_BUFFER_SIZE_ERROR 0xC3
#define POSTCODE_ROMSIG_MISMATCH_ERROR 0xC4
#define POSTCODE_PSP_COOKIE_MISMATCH_ERROR 0xC5
#define POSTCODE_BDT1_COOKIE_MISMATCH_ERROR 0xC6
#define POSTCODE_UPDATE_PSP_BIOS_DIR_ERROR 0xC7
#define POSTCODE_UNMAP_SPI_ROM 0xF0
#define POSTCODE_UNMAP_FCH_DEVICES 0xF1
#define POSTCODE_LEAVING_VERSTAGE 0xF2
#define SPI_ADDR_MASK 0x00ffffff
#define DEFAULT_WORKBUF_TRANSFER_SIZE (8 * KiB)
struct psp_ef_table {
uint32_t signature; /* 0x55aa55aa */
uint32_t reserved0[4];
uint32_t psp_table;
uint32_t bios0_entry;
uint32_t bios1_entry;
uint32_t bios2_entry;
} __attribute__((packed, aligned(16)));
void test_svc_calls(void);
uint32_t unmap_fch_devices(void);
uint32_t verstage_soc_early_init(void);
void verstage_soc_init(void);
uintptr_t *map_spi_rom(void);
void sb_enable_legacy_io(void);
#endif /* PSP_VERSTAGE_H */

View File

@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <bl_uapp/bl_syscall_public.h>
#include <console/console.h>
#include <reset.h>
#include <stdint.h>
void do_board_reset(void)
{
printk(BIOS_ERR, "Resetting the board now.\n");
svc_reset_system(RESET_TYPE_COLD);
}

View File

@ -0,0 +1,152 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include "svc.h"
#include <assert.h>
#include <bl_uapp/bl_syscall_public.h>
#include <stddef.h>
void svc_exit(uint32_t status)
{
uint32_t unused = 0;
SVC_CALL0(SVC_EXIT, unused);
}
uint32_t svc_map_user_stack(void *start_addr, void *end_addr, void *stack_va)
{
uint32_t retval = 0;
SVC_CALL3(SVC_MAP_USER_STACK, (uint32_t)start_addr,
(uint32_t)end_addr, stack_va, retval);
return retval;
}
void svc_debug_print(const char *string)
{
uint32_t unused = 0;
SVC_CALL1(SVC_DEBUG_PRINT, (uint32_t)string, unused);
}
void svc_debug_print_ex(uint32_t dword0,
uint32_t dword1, uint32_t dword2, uint32_t dword3)
{
uint32_t unused = 0;
SVC_CALL4(SVC_DEBUG_PRINT_EX, dword0, dword1, dword2, dword3, unused);
}
uint32_t svc_wait_10ns_multiple(uint32_t multiple)
{
uint32_t retval = 0;
SVC_CALL1(SVC_WAIT_10NS_MULTIPLE, multiple, retval);
return retval;
}
uint32_t svc_get_boot_mode(uint32_t *boot_mode)
{
uint32_t retval = 0;
SVC_CALL1(SVC_GET_BOOT_MODE, boot_mode, retval);
return retval;
}
void svc_delay_in_usec(uint32_t delay)
{
uint32_t unused = 0;
SVC_CALL1(SVC_DELAY_IN_MICRO_SECONDS, delay, unused);
}
uint32_t svc_get_spi_rom_info(SPIROM_INFO *spi_rom_info)
{
uint32_t retval = 0;
SVC_CALL1(SVC_GET_SPI_INFO, (uint32_t)spi_rom_info, retval);
return retval;
}
uint32_t svc_map_fch_dev(FCH_IO_DEVICE io_device,
uint32_t arg1, uint32_t arg2, void **io_device_axi_addr)
{
uint32_t retval = 0;
assert(io_device < FCH_IO_DEVICE_END);
SVC_CALL4(SVC_MAP_FCH_IO_DEVICE, io_device, arg1, arg2,
(uint32_t)io_device_axi_addr, retval);
return retval;
}
uint32_t svc_unmap_fch_dev(FCH_IO_DEVICE io_device, void *io_device_axi_addr)
{
uint32_t retval = 0;
assert(io_device < FCH_IO_DEVICE_END);
SVC_CALL2(SVC_UNMAP_FCH_IO_DEVICE, (uint32_t)io_device,
(uint32_t)io_device_axi_addr, retval);
return retval;
}
uint32_t svc_map_spi_rom(void *spi_rom_addr,
uint32_t size, void **spi_rom_axi_addr)
{
uint32_t retval = 0;
SVC_CALL3(SVC_MAP_SPIROM_DEVICE, spi_rom_addr, size,
(uint32_t)spi_rom_axi_addr, retval);
return retval;
}
uint32_t svc_unmap_spi_rom(void *spi_rom_addr)
{
uint32_t retval = 0;
SVC_CALL1(SVC_UNMAP_SPIROM_DEVICE, (uint32_t)spi_rom_addr, retval);
return retval;
}
uint32_t svc_update_psp_bios_dir(uint32_t *psp_dir_offset,
uint32_t *bios_dir_offset, DIR_OFFSET_OPERATION operation)
{
uint32_t retval = 0;
assert(operation < DIR_OFFSET_OPERATION_MAX);
SVC_CALL3(SVC_UPDATE_PSP_BIOS_DIR, (uint32_t)psp_dir_offset,
(uint32_t)bios_dir_offset, operation, retval);
return retval;
}
uint32_t svc_save_uapp_data(UAPP_COPYBUF type, void *address,
uint32_t size)
{
uint32_t retval = 0;
assert(type < UAPP_COPYBUF_MAX);
SVC_CALL3(SVC_COPY_DATA_FROM_UAPP, type, (uint32_t)address, size, retval);
return retval;
}
uint32_t svc_read_timer_val(PSP_TIMER_TYPE type, uint64_t *counter_value)
{
unsigned int retval = 0;
assert(type < PSP_TIMER_TYPE_MAX);
SVC_CALL2(SVC_READ_TIMER_VAL, type, counter_value, retval);
return retval;
}
uint32_t svc_reset_system(RESET_TYPE reset_type)
{
unsigned int retval = 0;
assert(reset_type < RESET_TYPE_MAX);
SVC_CALL1(SVC_RESET_SYSTEM, reset_type, retval);
return retval;
}
uint32_t svc_write_postcode(uint32_t postcode)
{
uint32_t retval = 0;
SVC_CALL1(SVC_WRITE_POSTCODE, postcode, retval);
return retval;
}
uint32_t svc_get_max_workbuf_size(uint32_t *size)
{
uint32_t retval = 0;
SVC_CALL1(SVC_GET_MAX_WORKBUF_SIZE, size, retval);
return retval;
}
uint32_t svc_crypto_sha(SHA_GENERIC_DATA *sha_op, SHA_OPERATION_MODE sha_mode)
{
uint32_t retval = 0;
SVC_CALL2(SVC_SHA, sha_op, sha_mode, retval);
return retval;
}

View File

@ -0,0 +1,57 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef PSP_VERSTAGE_SVC_H
#define PSP_VERSTAGE_SVC_H
#define SVC_CALL4(SVC_ID, R0, R1, R2, R3, Ret) \
__asm__ __volatile__ ( \
"mov r0, %[reg0]\n\t" \
"mov r1, %[reg1]\n\t" \
"mov r2, %[reg2]\n\t" \
"mov r3, %[reg3]\n\t" \
"svc %[id]\n\t" \
"mov %[result], r0\n\t" \
: [result] "=r" (Ret) /* output */ \
: [id] "i" (SVC_ID), [reg0] "r" (R0), [reg1] "r" (R1), [reg2] "r" (R2), \
[reg3] "r" (R3) /* input(s) */ \
: "r0", "r1", "r2", "r3", "memory", "cc" /* list of clobbered registers */);
#define SVC_CALL3(SVC_ID, R0, R1, R2, Ret) \
__asm__ __volatile__ ( \
"mov r0, %[reg0]\n\t" \
"mov r1, %[reg1]\n\t" \
"mov r2, %[reg2]\n\t" \
"svc %[id]\n\t" \
"mov %[result], r0\n\t" \
: [result] "=r" (Ret) /* output */ \
: [id] "i" (SVC_ID), [reg0] "r" (R0), [reg1] "r" (R1), [reg2] "r" (R2) \
: "r0", "r1", "r2", "memory", "cc" /* list of clobbered registers */);
#define SVC_CALL2(SVC_ID, R0, R1, Ret) \
__asm__ __volatile__ ( \
"mov r0, %[reg0]\n\t" \
"mov r1, %[reg1]\n\t" \
"svc %[id]\n\t" \
"mov %[result], r0\n\t" \
: [result] "=r" (Ret) /* output */ \
: [id] "i" (SVC_ID), [reg0] "r" (R0), [reg1] "r" (R1)/* input(s) */ \
: "r0", "r1", "memory", "cc" /* list of clobbered registers */);
#define SVC_CALL1(SVC_ID, R0, Ret) \
__asm__ __volatile__ ( \
"mov r0, %[reg0]\n\t" \
"svc %[id]\n\t" \
"mov %[result], r0\n\t" \
: [result] "=r" (Ret) /* output */ \
: [id] "i" (SVC_ID), [reg0] "r" (R0) /* input(s) */ \
: "r0", "memory", "cc" /* list of clobbered registers */);
#define SVC_CALL0(SVC_ID, Ret) \
__asm__ __volatile__ ( \
"svc %[id]\n\t" \
"mov %[result], r0\n\t" \
: [result] "=r" (Ret) /* output */ \
: [id] "I" (SVC_ID) /* input(s) */ \
: "memory", "cc" /* list of clobbered registers */);
#endif /* PSP_VERSTAGE_SVC_H */

View File

@ -0,0 +1,15 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <bl_uapp/bl_syscall_public.h>
#include <stdint.h>
#include <timer.h>
void timer_monotonic_get(struct mono_time *mt)
{
/* Chrono timer is based on a 25MHz clock */
uint64_t clk;
svc_read_timer_val(PSP_TIMER_TYPE_CHRONO, &clk);
mt->microseconds = clk / 25;
}

View File

@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <timestamp.h>
/* Stubs */
void timestamp_add_now(enum timestamp_id id)
{
}
void timestamp_add(enum timestamp_id id, uint64_t ts)
{
}
uint64_t timestamp_get(void)
{
return 0;
}

View File

@ -0,0 +1,104 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <2crypto.h>
#include <2return_codes.h>
#include <bl_uapp/bl_syscall_public.h>
#include <commonlib/bsd/helpers.h>
#include <console/console.h>
#include "psp_verstage.h"
#include <stddef.h>
#include <string.h>
#include <vb2_api.h>
static struct SHA_GENERIC_DATA_T sha_op;
static uint32_t sha_op_size_remaining;
static uint8_t __attribute__((aligned(32))) sha_hash[64];
vb2_error_t vb2ex_hwcrypto_digest_init(enum vb2_hash_algorithm hash_alg, uint32_t data_size)
{
printk(BIOS_DEBUG, "Calculating hash of %d bytes\n", data_size);
sha_op_size_remaining = data_size;
if (hash_alg == VB2_HASH_SHA256) {
sha_op.SHAType = SHA_TYPE_256;
sha_op.DigestLen = 32;
} else if (hash_alg == VB2_HASH_SHA512) {
sha_op.SHAType = SHA_TYPE_512;
sha_op.DigestLen = 64;
} else {
printk(BIOS_INFO, "Unsupported hash_alg %d!\n", hash_alg);
return VB2_ERROR_EX_HWCRYPTO_UNSUPPORTED;
}
/* Set init flag for first operation */
sha_op.Init = 1;
/* Clear eom flag until last operation */
sha_op.Eom = 0;
/* Need documentation on this b:157610147 */
sha_op.DataMemType = 2;
sha_op.Digest = sha_hash;
sha_op.IntermediateDigest = NULL;
sha_op.IntermediateMsgLen = 0;
return VB2_SUCCESS;
}
vb2_error_t vb2ex_hwcrypto_digest_extend(const uint8_t *buf, uint32_t size)
{
uint32_t retval;
sha_op.Data = (uint8_t *) buf;
if (!sha_op_size_remaining) {
printk(BIOS_ERR, "ERROR: got more data than expected.\n");
return VB2_ERROR_UNKNOWN;
}
while (size) {
sha_op.DataLen = size;
sha_op_size_remaining -= sha_op.DataLen;
/* Set eom flag for final operation */
if (sha_op_size_remaining == 0)
sha_op.Eom = 1;
retval = svc_crypto_sha(&sha_op, SHA_GENERIC);
if (retval) {
printk(BIOS_ERR, "ERROR: HW crypto failed - errorcode: %#x\n",
retval);
return VB2_ERROR_UNKNOWN;
}
/* Clear init flag after first operation */
if (sha_op.Init == 1)
sha_op.Init = 0;
size -= sha_op.DataLen;
}
return VB2_SUCCESS;
}
/* Copy the hash back to verstage */
vb2_error_t vb2ex_hwcrypto_digest_finalize(uint8_t *digest, uint32_t digest_size)
{
if (sha_op.Eom == 0) {
printk(BIOS_ERR, "ERROR: Got less data than expected.\n");
return VB2_ERROR_UNKNOWN;
}
if (digest_size != sha_op.DigestLen) {
printk(BIOS_ERR, "ERROR: Digest size does not match expected length.\n");
return VB2_ERROR_UNKNOWN;
}
memcpy(digest, sha_hash, digest_size);
return VB2_SUCCESS;
}