blob: be5d43b40dae290b776b01c4db523be9d9fa37db [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0-only */
#include <amdblocks/reset.h>
#include <amdblocks/smn.h>
#include <bootstate.h>
#include <console/console.h>
#include <cpu/amd/msr.h>
#include <device/mmio.h>
#include <types.h>
#include "psp_def.h"
#define PSB_STATUS_OFFSET 0x10994
#define FUSE_PLATFORM_SECURE_BOOT_EN BIT(24)
#define PSB_TEST_STATUS_MASK 0xff
#define PSB_FUSING_READY_MASK BIT(8)
/* PSB Test Status and Error Codes (doc#56654) */
#define PSB_TEST_STATUS_PASS 0x00
#define PSB_TEST_STATUS_FUSE_READ_ERR 0x3e
#define PSB_TEST_STATUS_BIOS_KEY_BAD_USAGE 0x81
#define PSB_TEST_STATUS_BIOS_RTM_SIG_NOENT 0x82
#define PSB_TEST_STATUS_BIOS_RTM_COPY_ERR 0x83
#define PSB_TEST_STATUS_BIOS_RTM_BAD_SIG 0x84
#define PSB_TEST_STATUS_BIOS_KEY_BAD_SIG 0x85
#define PSB_TEST_STATUS_PLATFORM_BAD_ID 0x86
#define PSB_TEST_STATUS_BIOS_COPY_BIT_UNSET 0x87
#define PSB_TEST_STATUS_BIOS_CA_BAD_SIG 0x8a
#define PSB_TEST_STATUS_BIOS_CA_BAD_USAGE 0x8b
#define PSB_TEST_STATUS_BIOS_KEY_BAD_REVISION 0x8c
#define FUSE_STATUS_SUCCESS 0x00
#define FUSE_STATUS_NOT_ALLOWED 0x09
#define FUSE_STATUS_FUSING_ERR 0x0a
#define FUSE_STATUS_BOOT_DONE 0x0b
static const char *psb_test_status_to_string(u32 status)
{
switch (status) {
case PSB_TEST_STATUS_PASS:
return "Psb Test Status PASS";
case PSB_TEST_STATUS_FUSE_READ_ERR:
return "Error reading fuse info";
case PSB_TEST_STATUS_BIOS_KEY_BAD_USAGE:
return "OEM BIOS signing key usage flag violation";
case PSB_TEST_STATUS_BIOS_RTM_SIG_NOENT:
return "BIOS RTM signature entry not found";
case PSB_TEST_STATUS_BIOS_RTM_COPY_ERR:
return "BIOS copy to DRAM failed";
case PSB_TEST_STATUS_BIOS_RTM_BAD_SIG:
return "BIOS RTM signature verification failed";
case PSB_TEST_STATUS_BIOS_KEY_BAD_SIG:
return "OEM BIOS signing key failed signature verification";
case PSB_TEST_STATUS_PLATFORM_BAD_ID:
return "Platform vendor id and/or model id binding violation";
case PSB_TEST_STATUS_BIOS_COPY_BIT_UNSET:
return "BIOS copy bit unset for reset image";
case PSB_TEST_STATUS_BIOS_CA_BAD_SIG:
return "OEM BIOS signing CA key failed signature verification";
case PSB_TEST_STATUS_BIOS_CA_BAD_USAGE:
return "OEM BIOS signing CA key usage flag violation";
case PSB_TEST_STATUS_BIOS_KEY_BAD_REVISION:
return "OEM BIOS signing key revision violation";
default:
return "Unknown failure";
}
}
static const char *fuse_status_to_string(u32 status)
{
switch (status) {
case FUSE_STATUS_SUCCESS:
return "PSB Fusing completed successfully";
case FUSE_STATUS_NOT_ALLOWED:
return "Fusing not allowed or already done";
case FUSE_STATUS_FUSING_ERR:
return "Fuse programming failed";
case FUSE_STATUS_BOOT_DONE:
return "Issued after BOOT DONE";
default:
return "Unknown failure";
}
}
static uint32_t get_psb_status(void)
{
return smn_read32(SMN_PSP_PUBLIC_BASE + PSB_STATUS_OFFSET);
}
/*
* Request Platform Secure Boot enablement via the PSP if it is not already
* enabled. Upon receiving this command, the PSP will program all PSB fuses
* so long as the BIOS signing key token is valid.
*/
static enum cb_err psb_enable(void)
{
u32 status;
struct mbox_default_buffer buffer = {
.header = {
.size = sizeof(buffer)
}
};
status = get_psb_status();
printk(BIOS_INFO, "PSB: Status = %x\n", status);
if (status & FUSE_PLATFORM_SECURE_BOOT_EN) {
printk(BIOS_DEBUG, "PSB: Already enabled\n");
return CB_SUCCESS;
}
status = soc_read_c2p38();
printk(BIOS_INFO, "PSB: HSTI = %x\n", status);
const u32 psb_test_status = status & PSB_TEST_STATUS_MASK;
if (psb_test_status != PSB_TEST_STATUS_PASS) {
printk(BIOS_ERR, "PSB: %s\n", psb_test_status_to_string(psb_test_status));
return CB_ERR;
}
if (!(status & PSB_FUSING_READY_MASK)) {
printk(BIOS_ERR, "PSB: Fusing not allowed\n");
return CB_ERR;
}
printk(BIOS_DEBUG, "PSB: Enable... ");
const int cmd_status = send_psp_command(MBOX_BIOS_CMD_PSB_AUTO_FUSING, &buffer);
psp_print_cmd_status(cmd_status, &buffer.header);
if (cmd_status) {
printk(BIOS_ERR, "PSB: Fusing request failed: %d\n", cmd_status);
return CB_ERR;
}
const u32 fuse_status = read32(&buffer.header.status);
if (fuse_status != FUSE_STATUS_SUCCESS) {
printk(BIOS_ERR, "PSB: %s\n", fuse_status_to_string(fuse_status));
return CB_ERR;
}
printk(BIOS_NOTICE, "PSB: Rebooting\n");
cold_reset();
}
static void enable_secure_boot(void *unused)
{
/*
* Enable secure boot before loading payload. Psb fusing is done late in
* boot process to avoid any fuse access conflicts with other components
* which happens during boot process.
*/
if (psb_enable() == CB_ERR)
printk(BIOS_NOTICE, "Enabling PSB failed.\n");
}
BOOT_STATE_INIT_ENTRY(BS_PAYLOAD_LOAD, BS_ON_ENTRY, enable_secure_boot, NULL);