From d6b7236732d8cc74545849f4b81af1d33e8758e2 Mon Sep 17 00:00:00 2001 From: Marshall Dawson Date: Thu, 5 Mar 2020 11:44:24 -0700 Subject: soc/amd/common/psp: Split mailbox support into v1 and v2 Family 17h redefines the PSP command and status, and therefore the steps required to send commands via the mailbox. Convert the existing version into a v1 and add a v2. New Kconfig options allow the soc to choose v1 vs. v2. The v2 PSP begins responding to the mailbox command when the full bit range is written. Define the new mailbox as a union of a u32 and a structure. Additional PSP details may be found in the NDA publication (#55758) AMD Platform Security Processor BIOS Architecture Design Guide for AMD Family 17h Processors Change the existing two soc functions that return pointers to void pointers. BUG=b:153677737 Signed-off-by: Marshall Dawson Signed-off-by: Felix Held Change-Id: I4d358fdae07da471640856f57568059e9487f6a8 Reviewed-on: https://review.coreboot.org/c/coreboot/+/40293 Tested-by: build bot (Jenkins) Reviewed-by: Angel Pons --- src/soc/amd/common/block/include/amdblocks/psp.h | 2 +- src/soc/amd/common/block/psp/Kconfig | 13 ++- src/soc/amd/common/block/psp/Makefile.inc | 11 +++ src/soc/amd/common/block/psp/psp.c | 85 ------------------ src/soc/amd/common/block/psp/psp_def.h | 36 ++++++-- src/soc/amd/common/block/psp/psp_gen1.c | 93 ++++++++++++++++++++ src/soc/amd/common/block/psp/psp_gen2.c | 104 +++++++++++++++++++++++ src/soc/amd/stoneyridge/Kconfig | 2 +- src/soc/amd/stoneyridge/psp.c | 4 +- 9 files changed, 253 insertions(+), 97 deletions(-) create mode 100644 src/soc/amd/common/block/psp/psp_gen1.c create mode 100644 src/soc/amd/common/block/psp/psp_gen2.c (limited to 'src') diff --git a/src/soc/amd/common/block/include/amdblocks/psp.h b/src/soc/amd/common/block/include/amdblocks/psp.h index 36e110867a..53946fb8d2 100644 --- a/src/soc/amd/common/block/include/amdblocks/psp.h +++ b/src/soc/amd/common/block/include/amdblocks/psp.h @@ -5,7 +5,7 @@ #define __AMD_PSP_H__ /* Get the mailbox base address - specific to family of device. */ -struct psp_mbox *soc_get_mbox_address(void); +void *soc_get_mbox_address(void); /* BIOS-to-PSP functions return 0 if successful, else negative value */ #define PSPSTS_SUCCESS 0 diff --git a/src/soc/amd/common/block/psp/Kconfig b/src/soc/amd/common/block/psp/Kconfig index 0517a2f33f..9466cc6abd 100644 --- a/src/soc/amd/common/block/psp/Kconfig +++ b/src/soc/amd/common/block/psp/Kconfig @@ -3,7 +3,18 @@ config SOC_AMD_COMMON_BLOCK_PSP default n help This option builds in the Platform Security Processor initialization - functions. + functions. Do not select this directly in SoC code, select + SOC_AMD_COMMON_BLOCK_PSP_GENx instead. + +config SOC_AMD_COMMON_BLOCK_PSP_GEN1 + bool + default n + select SOC_AMD_COMMON_BLOCK_PSP + +config SOC_AMD_COMMON_BLOCK_PSP_GEN2 + bool + default n + select SOC_AMD_COMMON_BLOCK_PSP config SOC_AMD_PSP_SELECTABLE_SMU_FW bool diff --git a/src/soc/amd/common/block/psp/Makefile.inc b/src/soc/amd/common/block/psp/Makefile.inc index 2f5de1df9c..dc9a385e39 100644 --- a/src/soc/amd/common/block/psp/Makefile.inc +++ b/src/soc/amd/common/block/psp/Makefile.inc @@ -1,4 +1,15 @@ bootblock-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP) += psp.c +bootblock-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP_GEN1) += psp_gen1.c +bootblock-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP_GEN2) += psp_gen2.c + romstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP) += psp.c +romstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP_GEN1) += psp_gen1.c +romstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP_GEN2) += psp_gen2.c + ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP) += psp.c +ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP_GEN1) += psp_gen1.c +ramstage-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP_GEN2) += psp_gen2.c + smm-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP) += psp.c +smm-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP_GEN1) += psp_gen1.c +smm-$(CONFIG_SOC_AMD_COMMON_BLOCK_PSP_GEN2) += psp_gen2.c diff --git a/src/soc/amd/common/block/psp/psp.c b/src/soc/amd/common/block/psp/psp.c index c35f41b20c..22404be6d6 100644 --- a/src/soc/amd/common/block/psp/psp.c +++ b/src/soc/amd/common/block/psp/psp.c @@ -6,10 +6,8 @@ #include #include #include -#include #include #include -#include #include #include #include @@ -43,94 +41,11 @@ static const char *status_to_string(int err) } } -static u32 rd_mbox_sts(struct psp_mbox *mbox) -{ - return read32(&mbox->mbox_status); -} - -static void wr_mbox_cmd(struct psp_mbox *mbox, u32 cmd) -{ - write32(&mbox->mbox_command, cmd); -} - -static u32 rd_mbox_cmd(struct psp_mbox *mbox) -{ - return read32(&mbox->mbox_command); -} - -static void wr_mbox_cmd_resp(struct psp_mbox *mbox, void *buffer) -{ - write64(&mbox->cmd_response, (uintptr_t)buffer); -} - static u32 rd_resp_sts(struct mbox_default_buffer *buffer) { return read32(&buffer->header.status); } -static int wait_initialized(struct psp_mbox *mbox) -{ - struct stopwatch sw; - - stopwatch_init_msecs_expire(&sw, PSP_INIT_TIMEOUT); - - do { - if (rd_mbox_sts(mbox) & STATUS_INITIALIZED) - return 0; - } while (!stopwatch_expired(&sw)); - - return -PSPSTS_INIT_TIMEOUT; -} - -static int wait_command(struct psp_mbox *mbox) -{ - struct stopwatch sw; - - stopwatch_init_msecs_expire(&sw, PSP_CMD_TIMEOUT); - - do { - if (!rd_mbox_cmd(mbox)) - return 0; - } while (!stopwatch_expired(&sw)); - - return -PSPSTS_CMD_TIMEOUT; -} - -static int send_psp_command(u32 command, void *buffer) -{ - struct psp_mbox *mbox = soc_get_mbox_address(); - if (!mbox) - return -PSPSTS_NOBASE; - - /* check for PSP error conditions */ - if (rd_mbox_sts(mbox) & STATUS_HALT) - return -PSPSTS_HALTED; - - if (rd_mbox_sts(mbox) & STATUS_RECOVERY) - return -PSPSTS_RECOVERY; - - /* PSP must be finished with init and ready to accept a command */ - if (wait_initialized(mbox)) - return -PSPSTS_INIT_TIMEOUT; - - if (wait_command(mbox)) - return -PSPSTS_CMD_TIMEOUT; - - /* set address of command-response buffer and write command register */ - wr_mbox_cmd_resp(mbox, buffer); - wr_mbox_cmd(mbox, command); - - /* PSP clears command register when complete */ - if (wait_command(mbox)) - return -PSPSTS_CMD_TIMEOUT; - - /* check delivery status */ - if (rd_mbox_sts(mbox) & (STATUS_ERROR | STATUS_TERMINATED)) - return -PSPSTS_SEND_ERROR; - - return 0; -} - /* * Print meaningful status to the console. Caller only passes a pointer to a * buffer if it's expected to contain its own status. diff --git a/src/soc/amd/common/block/psp/psp_def.h b/src/soc/amd/common/block/psp/psp_def.h index 4b3ca6a352..37755166f0 100644 --- a/src/soc/amd/common/block/psp/psp_def.h +++ b/src/soc/amd/common/block/psp/psp_def.h @@ -5,6 +5,7 @@ #define __AMD_PSP_DEF_H__ #include +#include /* x86 to PSP commands */ #define MBOX_BIOS_CMD_DRAM_INFO 0x01 @@ -20,24 +21,42 @@ #define MBOX_BIOS_CMD_SMU_FW2 0x1a #define MBOX_BIOS_CMD_ABORT 0xfe -/* generic PSP interface status */ -#define STATUS_INITIALIZED 0x1 -#define STATUS_ERROR 0x2 -#define STATUS_TERMINATED 0x4 -#define STATUS_HALT 0x8 -#define STATUS_RECOVERY 0x10 +/* generic PSP interface status, v1 */ +#define PSPV1_STATUS_INITIALIZED BIT(0) +#define PSPV1_STATUS_ERROR BIT(1) +#define PSPV1_STATUS_TERMINATED BIT(2) +#define PSPV1_STATUS_HALT BIT(3) +#define PSPV1_STATUS_RECOVERY BIT(4) + +/* generic PSP interface status, v2 */ +#define PSPV2_STATUS_ERROR BIT(30) +#define PSPV2_STATUS_RECOVERY BIT(31) /* psp_mbox consists of hardware registers beginning at PSPx000070 * mbox_command: BIOS->PSP command, cleared by PSP when complete * mbox_status: BIOS->PSP interface status * cmd_response: pointer to command/response buffer */ -struct psp_mbox { +struct pspv1_mbox { u32 mbox_command; u32 mbox_status; u64 cmd_response; /* definition conflicts w/BKDG but matches agesa */ } __packed; +struct pspv2_mbox { + union { + u32 val; + struct pspv2_mbox_cmd_fields { + u16 mbox_status; + u8 mbox_command; + u32 reserved:6; + u32 recovery:1; + u32 ready:1; + } __packed fields; + }; + u64 cmd_response; +} __packed; + /* command/response format, BIOS builds this in memory * mbox_buffer_header: generic header * mbox_buffer: command-specific buffer format @@ -70,4 +89,7 @@ struct mbox_cmd_sx_info_buffer { #define PSP_INIT_TIMEOUT 10000 /* 10 seconds */ #define PSP_CMD_TIMEOUT 1000 /* 1 second */ +/* This command needs to be implemented by the generation specific code. */ +int send_psp_command(u32 command, void *buffer); + #endif /* __AMD_PSP_DEF_H__ */ diff --git a/src/soc/amd/common/block/psp/psp_gen1.c b/src/soc/amd/common/block/psp/psp_gen1.c new file mode 100644 index 0000000000..0e5aa30154 --- /dev/null +++ b/src/soc/amd/common/block/psp/psp_gen1.c @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* This file is part of the coreboot project. */ + +#include +#include +#include +#include +#include +#include +#include "psp_def.h" + +static u32 rd_mbox_sts(struct pspv1_mbox *mbox) +{ + return read32(&mbox->mbox_status); +} + +static void wr_mbox_cmd(struct pspv1_mbox *mbox, u32 cmd) +{ + write32(&mbox->mbox_command, cmd); +} + +static u32 rd_mbox_cmd(struct pspv1_mbox *mbox) +{ + return read32(&mbox->mbox_command); +} + +static void wr_mbox_cmd_resp(struct pspv1_mbox *mbox, void *buffer) +{ + write64(&mbox->cmd_response, (uintptr_t)buffer); +} + +static int wait_initialized(struct pspv1_mbox *mbox) +{ + struct stopwatch sw; + + stopwatch_init_msecs_expire(&sw, PSP_INIT_TIMEOUT); + + do { + if (rd_mbox_sts(mbox) & PSPV1_STATUS_INITIALIZED) + return 0; + } while (!stopwatch_expired(&sw)); + + return -PSPSTS_INIT_TIMEOUT; +} + +static int wait_command(struct pspv1_mbox *mbox) +{ + struct stopwatch sw; + + stopwatch_init_msecs_expire(&sw, PSP_CMD_TIMEOUT); + + do { + if (!rd_mbox_cmd(mbox)) + return 0; + } while (!stopwatch_expired(&sw)); + + return -PSPSTS_CMD_TIMEOUT; +} + +int send_psp_command(u32 command, void *buffer) +{ + struct pspv1_mbox *mbox = soc_get_mbox_address(); + if (!mbox) + return -PSPSTS_NOBASE; + + /* check for PSP error conditions */ + if (rd_mbox_sts(mbox) & PSPV1_STATUS_HALT) + return -PSPSTS_HALTED; + + if (rd_mbox_sts(mbox) & PSPV1_STATUS_RECOVERY) + return -PSPSTS_RECOVERY; + + /* PSP must be finished with init and ready to accept a command */ + if (wait_initialized(mbox)) + return -PSPSTS_INIT_TIMEOUT; + + if (wait_command(mbox)) + return -PSPSTS_CMD_TIMEOUT; + + /* set address of command-response buffer and write command register */ + wr_mbox_cmd_resp(mbox, buffer); + wr_mbox_cmd(mbox, command); + + /* PSP clears command register when complete */ + if (wait_command(mbox)) + return -PSPSTS_CMD_TIMEOUT; + + /* check delivery status */ + if (rd_mbox_sts(mbox) & (PSPV1_STATUS_ERROR | PSPV1_STATUS_TERMINATED)) + return -PSPSTS_SEND_ERROR; + + return 0; +} diff --git a/src/soc/amd/common/block/psp/psp_gen2.c b/src/soc/amd/common/block/psp/psp_gen2.c new file mode 100644 index 0000000000..b70babc14a --- /dev/null +++ b/src/soc/amd/common/block/psp/psp_gen2.c @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* This file is part of the coreboot project. */ + +#include +#include +#include +#include +#include +#include +#include "psp_def.h" + +static u16 rd_mbox_sts(struct pspv2_mbox *mbox) +{ + union { + u32 val; + struct pspv2_mbox_cmd_fields fields; + } tmp = { 0 }; + + tmp.val = read32(&mbox->val); + return tmp.fields.mbox_status; +} + +static void wr_mbox_cmd(struct pspv2_mbox *mbox, u8 cmd) +{ + union { + u32 val; + struct pspv2_mbox_cmd_fields fields; + } tmp = { 0 }; + + /* Write entire 32-bit area to begin command execution */ + tmp.fields.mbox_command = cmd; + write32(&mbox->val, tmp.val); +} + +static u8 rd_mbox_recovery(struct pspv2_mbox *mbox) +{ + union { + u32 val; + struct pspv2_mbox_cmd_fields fields; + } tmp = { 0 }; + + tmp.val = read32(&mbox->val); + return !!tmp.fields.recovery; +} + +static void wr_mbox_cmd_resp(struct pspv2_mbox *mbox, void *buffer) +{ + write64(&mbox->cmd_response, (uintptr_t)buffer); +} + +static int wait_command(struct pspv2_mbox *mbox, bool wait_for_ready) +{ + struct pspv2_mbox and_mask = { .val = ~0 }; + struct pspv2_mbox expected = { .val = 0 }; + struct stopwatch sw; + u32 tmp; + + /* Zero fields from and_mask that should be kept */ + and_mask.fields.mbox_command = 0; + and_mask.fields.ready = wait_for_ready ? 0 : 1; + + /* Expect mbox_cmd == 0 but ready depends */ + if (wait_for_ready) + expected.fields.ready = 1; + + stopwatch_init_msecs_expire(&sw, PSP_CMD_TIMEOUT); + + do { + tmp = read32(&mbox->val); + tmp &= ~and_mask.val; + if (tmp == expected.val) + return 0; + } while (!stopwatch_expired(&sw)); + + return -PSPSTS_CMD_TIMEOUT; +} + +int send_psp_command(u32 command, void *buffer) +{ + struct pspv2_mbox *mbox = soc_get_mbox_address(); + if (!mbox) + return -PSPSTS_NOBASE; + + if (rd_mbox_recovery(mbox)) + return -PSPSTS_RECOVERY; + + if (wait_command(mbox, true)) + return -PSPSTS_CMD_TIMEOUT; + + /* set address of command-response buffer and write command register */ + wr_mbox_cmd_resp(mbox, buffer); + wr_mbox_cmd(mbox, command); + + /* PSP clears command register when complete. All commands except + * SxInfo set the Ready bit. */ + if (wait_command(mbox, command != MBOX_BIOS_CMD_SX_INFO)) + return -PSPSTS_CMD_TIMEOUT; + + /* check delivery status */ + if (rd_mbox_sts(mbox)) + return -PSPSTS_SEND_ERROR; + + return 0; +} diff --git a/src/soc/amd/stoneyridge/Kconfig b/src/soc/amd/stoneyridge/Kconfig index 14615888e3..d73f3153e8 100644 --- a/src/soc/amd/stoneyridge/Kconfig +++ b/src/soc/amd/stoneyridge/Kconfig @@ -47,7 +47,7 @@ config CPU_SPECIFIC_OPTIONS select SOC_AMD_COMMON_BLOCK_HDA select SOC_AMD_COMMON_BLOCK_SATA select SOC_AMD_COMMON_BLOCK_PI - select SOC_AMD_COMMON_BLOCK_PSP + select SOC_AMD_COMMON_BLOCK_PSP_GEN1 select SOC_AMD_COMMON_BLOCK_CAR select SOC_AMD_COMMON_BLOCK_S3 select SOC_AMD_COMMON_BLOCK_SMBUS diff --git a/src/soc/amd/stoneyridge/psp.c b/src/soc/amd/stoneyridge/psp.c index bc2d725145..88bd61d4dd 100644 --- a/src/soc/amd/stoneyridge/psp.c +++ b/src/soc/amd/stoneyridge/psp.c @@ -30,7 +30,7 @@ void soc_enable_psp_early(void) pci_write_config32(SOC_PSP_DEV, PCI_COMMAND, cmd); }; -struct psp_mbox *soc_get_mbox_address(void) +void *soc_get_mbox_address(void) { uintptr_t psp_mmio; @@ -54,5 +54,5 @@ struct psp_mbox *soc_get_mbox_address(void) ~PCI_BASE_ADDRESS_MEM_ATTR_MASK; } - return (struct psp_mbox *)(psp_mmio + PSP_MAILBOX_OFFSET); + return (void *)(psp_mmio + PSP_MAILBOX_OFFSET); } -- cgit v1.2.3