Attention is currently required from: Fred Reitberger, Jason Glenesk, Matt DeVillier, ritul guru.
Hello ritul guru,
I'd like you to do a code review. Please visit
https://review.coreboot.org/c/coreboot/+/83740?usp=email
to review the following change.
Change subject: [WIP] soc/amd/common/psp_smi: implement P2C mailbox handling ......................................................................
[WIP] soc/amd/common/psp_smi: implement P2C mailbox handling
When the PSP wants to access the SPI flash during runtime, but isn't the owner of the SPI flash controller, it sends an SMI to the x86 side. The corresponding SMI handler then checks the P2C (PSP to core) mailbox for the command and data, processes the command, and if needed puts the requested data into the P2C buffer.
The P2C mailbox is a memory region in TSEG aka SMM memory. Both location and size are communicated to the PSP via the PSP SMM info mailbox command which is sent right after mpinit is done.
This commit adds the code to access the P2C mailbox to the PSP SMI handler code, but the handling of the actual mailbox commands the PSP sends to the SMI handler is added in later patches to keep the patch size manageable.
This patch is a heavily reworked version of parts of CB:65523.
Document #55758 Rev. 2.04 was used as a reference.
TODO: Check if all wbinvd calls are needed
Test=TODO, but when selecting SOC_AMD_COMMON_BLOCK_PSP_SMI, Mandolin still builds
Signed-off-by: Felix Held felix-coreboot@felixheld.de Signed-off-by: Ritul Guru ritul.bits@gmail.com Change-Id: I50479bed2332addae652026c6818460eeb6403af --- M src/soc/amd/common/block/psp/psp_def.h M src/soc/amd/common/block/psp/psp_smi.c M src/soc/amd/common/block/psp/psp_smm.c 3 files changed, 173 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/40/83740/1
diff --git a/src/soc/amd/common/block/psp/psp_def.h b/src/soc/amd/common/block/psp/psp_def.h index 72569ea..de4a6a0 100644 --- a/src/soc/amd/common/block/psp/psp_def.h +++ b/src/soc/amd/common/block/psp/psp_def.h @@ -120,4 +120,6 @@
enum cb_err soc_read_c2p38(uint32_t *msg_38_value);
+void enable_psp_smi(void); + #endif /* __AMD_PSP_DEF_H__ */ diff --git a/src/soc/amd/common/block/psp/psp_smi.c b/src/soc/amd/common/block/psp/psp_smi.c index b94366c..6f78d77 100644 --- a/src/soc/amd/common/block/psp/psp_smi.c +++ b/src/soc/amd/common/block/psp/psp_smi.c @@ -1,7 +1,177 @@ /* SPDX-License-Identifier: GPL-2.0-only */
#include <amdblocks/psp.h> +#include <amdblocks/smi.h> +#include <console/console.h> +#include <cpu/x86/cache.h> +#include <device/mmio.h> +#include <types.h> +#include "psp_def.h" + +extern struct { + u8 buffer[P2C_BUFFER_MAXSIZE]; +} __aligned(32) p2c_buffer; + +static const uintptr_t p2c_mbox_base = (uintptr_t)&p2c_buffer.buffer; + +#define P2C_MBOX_COMMAND_OFFSET 0x00 +#define P2C_MBOX_STATUS_OFFSET 0x04 +#define P2C_MBOX_BUFFER_OFFSET 0x08 + +union p2c_mbox_status { + struct { + u32 checksum : 8; /* [ 0.. 7] */ + u32 checksum_en : 1; /* [ 8.. 8] */ + u32 reserved : 22; /* [ 9..30] */ + u32 command_ready : 1; /* [31..31] */ + }; + u32 raw; +}; + +/* PSP to x86 status */ +enum mbox_p2c_status { + MBOX_PSP_SUCCESS = 0x00, + MBOX_PSP_INVALID_PARAMETER = 0x01, + MBOX_PSP_CRC_ERROR = 0x02, + MBOX_PSP_COMMAND_PROCESS_ERROR = 0x04, + MBOX_PSP_UNSUPPORTED = 0x08, + MBOX_PSP_SPI_BUSY_ASYNC = 0x0a, + MBOX_PSP_SPI_BUSY = 0x0b, +}; + +static u8 rd_bios_mbox_checksum(void) +{ + union p2c_mbox_status tmp; + + tmp.raw = read32p(p2c_mbox_base + P2C_MBOX_STATUS_OFFSET); + return tmp.checksum; +} + +static void wr_bios_mbox_checksum(u8 checksum) +{ + union p2c_mbox_status tmp; + + tmp.raw = read32p(p2c_mbox_base + P2C_MBOX_STATUS_OFFSET); + tmp.checksum = checksum; + write32p(p2c_mbox_base + P2C_MBOX_STATUS_OFFSET, tmp.raw); +} + +static bool rd_bios_mbox_checksum_en(void) +{ + union p2c_mbox_status tmp; + + tmp.raw = read32p(p2c_mbox_base + P2C_MBOX_STATUS_OFFSET); + return !!tmp.checksum_en; +} + +static void wr_bios_mbox_ready(bool ready) +{ + union p2c_mbox_status tmp; + + tmp.raw = read32p(p2c_mbox_base + P2C_MBOX_STATUS_OFFSET); + tmp.command_ready = ready; + write32p(p2c_mbox_base + P2C_MBOX_STATUS_OFFSET, tmp.raw); +} + +void enable_psp_smi(void) +{ + wr_bios_mbox_ready(true); +} + +static void disable_psp_smi(void) +{ + wr_bios_mbox_ready(false); +} + +static void clear_psp_command(void) +{ + write32p(p2c_mbox_base + P2C_MBOX_COMMAND_OFFSET, 0); +} + +static u32 get_psp_command(void) +{ + return read32p(p2c_mbox_base + P2C_MBOX_COMMAND_OFFSET); +} + +static struct mbox_default_buffer *get_psp_command_buffer(void) +{ + return (struct mbox_default_buffer *)(p2c_mbox_base + P2C_MBOX_BUFFER_OFFSET); +} + +static uint32_t get_psp_cmd_buffer_length(void) +{ + return read32(&get_psp_command_buffer()->header.size); +} + +static u8 calc_psp_buffer_checksum8(void) +{ + const uint8_t *data = (const u8 *)get_psp_command_buffer(); + const size_t size = get_psp_cmd_buffer_length(); + u8 checksum = 0; + size_t i; + + for (i = 0; i < size; i++) + checksum += read8(data + i); + + return checksum; +} + +static void write_psp_cmd_buffer_status(uint32_t status) +{ + return write32(&get_psp_command_buffer()->header.status, status); +} + +static enum mbox_p2c_status check_psp_command(void) +{ + if (rd_bios_mbox_checksum_en() && + calc_psp_buffer_checksum8() != rd_bios_mbox_checksum()) + return MBOX_PSP_CRC_ERROR; + + if (get_psp_cmd_buffer_length() > P2C_BUFFER_MAXSIZE - P2C_MBOX_BUFFER_OFFSET) + return MBOX_PSP_INVALID_PARAMETER; + + return MBOX_PSP_SUCCESS; +} + +static void handle_psp_command(void) +{ + enum mbox_p2c_status status; + u32 cmd; + + status = check_psp_command(); + if (status != MBOX_PSP_SUCCESS) + goto out; + + cmd = get_psp_command(); + + switch (cmd) { + default: + printk(BIOS_ERR, "PSP: Unknown command %d\n", cmd); + status = MBOX_PSP_UNSUPPORTED; + break; + } + +out: + write_psp_cmd_buffer_status(status); + + if (status == MBOX_PSP_SUCCESS && rd_bios_mbox_checksum_en()) + wr_bios_mbox_checksum(calc_psp_buffer_checksum8()); +}
void psp_smi_handler(void) { + disable_psp_smi(); + + wbinvd(); + + handle_psp_command(); + + wbinvd(); + + clear_psp_command(); + enable_psp_smi(); + + wbinvd(); + + reset_psp_smi(); } diff --git a/src/soc/amd/common/block/psp/psp_smm.c b/src/soc/amd/common/block/psp/psp_smm.c index 4f76ebc..00e00dd 100644 --- a/src/soc/amd/common/block/psp/psp_smm.c +++ b/src/soc/amd/common/block/psp/psp_smm.c @@ -92,6 +92,7 @@
if (CONFIG(SOC_AMD_COMMON_BLOCK_PSP_SMI)) { configure_psp_smi(); + enable_psp_smi(); }
printk(BIOS_DEBUG, "PSP: Notify SMM info... ");