diff options
author | Felix Held <felix-coreboot@felixheld.de> | 2024-08-02 02:29:20 +0200 |
---|---|---|
committer | Felix Held <felix-coreboot@felixheld.de> | 2024-08-07 16:32:13 +0000 |
commit | 2b6070bed477124bbe18a0688e4494212d2c101a (patch) | |
tree | e879755cce1bae40d9287b00f2ce61b504424a50 /src | |
parent | 35946f957affc2e23830750dbf2a26586093ca76 (diff) |
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.
Test=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
Reviewed-on: https://review.coreboot.org/c/coreboot/+/83740
Reviewed-by: Martin Roth <martin.roth@amd.corp-partner.google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Matt DeVillier <matt.devillier@amd.corp-partner.google.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/soc/amd/common/block/psp/psp_def.h | 13 | ||||
-rw-r--r-- | src/soc/amd/common/block/psp/psp_smi.c | 160 | ||||
-rw-r--r-- | src/soc/amd/common/block/psp/psp_smm.c | 1 |
3 files changed, 174 insertions, 0 deletions
diff --git a/src/soc/amd/common/block/psp/psp_def.h b/src/soc/amd/common/block/psp/psp_def.h index 72569ea357..d58aa0b82e 100644 --- a/src/soc/amd/common/block/psp/psp_def.h +++ b/src/soc/amd/common/block/psp/psp_def.h @@ -111,6 +111,17 @@ struct mbox_cmd_dtpm_config_buffer { #define C2P_BUFFER_MAXSIZE 0xc00 /* Core-to-PSP buffer */ #define P2C_BUFFER_MAXSIZE 0xc00 /* PSP-to-core buffer */ +/* 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, +}; + uintptr_t get_psp_mmio_base(void); void psp_print_cmd_status(int cmd_status, struct mbox_buffer_header *header); @@ -120,4 +131,6 @@ int send_psp_command(u32 command, void *buffer); 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 b94366ca5a..e6cc1dc96c 100644 --- a/src/soc/amd/common/block/psp/psp_smi.c +++ b/src/soc/amd/common/block/psp/psp_smi.c @@ -1,7 +1,167 @@ /* 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] */ + } __packed fields; + u32 raw; +}; + +static u8 rd_bios_mbox_checksum(void) +{ + union p2c_mbox_status status; + + status.raw = read32p(p2c_mbox_base + P2C_MBOX_STATUS_OFFSET); + return status.fields.checksum; +} + +static void wr_bios_mbox_checksum(u8 checksum) +{ + union p2c_mbox_status status; + + status.raw = read32p(p2c_mbox_base + P2C_MBOX_STATUS_OFFSET); + status.fields.checksum = checksum; + write32p(p2c_mbox_base + P2C_MBOX_STATUS_OFFSET, status.raw); +} + +static bool rd_bios_mbox_checksum_en(void) +{ + union p2c_mbox_status status; + + status.raw = read32p(p2c_mbox_base + P2C_MBOX_STATUS_OFFSET); + return !!status.fields.checksum_en; +} + +static void wr_bios_mbox_ready(bool ready) +{ + union p2c_mbox_status status; + + status.raw = read32p(p2c_mbox_base + P2C_MBOX_STATUS_OFFSET); + status.fields.command_ready = ready; + write32p(p2c_mbox_base + P2C_MBOX_STATUS_OFFSET, status.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(enum mbox_p2c_status 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()); +} + +/* TODO: check if all wbinvd() calls are necessary */ 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 4f76ebc421..00e00dd261 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 @@ int psp_notify_smm(void) if (CONFIG(SOC_AMD_COMMON_BLOCK_PSP_SMI)) { configure_psp_smi(); + enable_psp_smi(); } printk(BIOS_DEBUG, "PSP: Notify SMM info... "); |