[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC PATCH 3/7] slaunch/psp: Add core PSP commands and get capability co
From: |
Sergii Dmytruk |
Subject: |
[RFC PATCH 3/7] slaunch/psp: Add core PSP commands and get capability command |
Date: |
Wed, 18 Dec 2024 21:07:59 +0200 |
From: Alec Brown <alec.r.brown@oracle.com>
Add various core DRTM commands for the PSP.
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii.dmytruk@3mdeb.com>
---
grub-core/loader/slaunch/psp.c | 235 ++++++++++++++++++++++++++++++++-
include/grub/i386/psp.h | 48 +++++++
2 files changed, 281 insertions(+), 2 deletions(-)
diff --git a/grub-core/loader/slaunch/psp.c b/grub-core/loader/slaunch/psp.c
index 3459f7e34..2bbb4c685 100644
--- a/grub-core/loader/slaunch/psp.c
+++ b/grub-core/loader/slaunch/psp.c
@@ -33,6 +33,8 @@
#include <grub/types.h>
#include <grub/misc.h>
#include <grub/err.h>
+#include <grub/mm.h>
+#include <grub/time.h>
#include <grub/pci.h>
#include <grub/i386/pci.h>
#include <grub/i386/psp.h>
@@ -53,10 +55,71 @@ typedef enum
PSP_V3
} psp_version_t;
+struct pci_psp_device
+{
+ grub_uint16_t vendor_id;
+ grub_uint16_t dev_id;
+ psp_version_t version;
+};
+
+static const struct pci_psp_device psp_devs_list[] = {
+ {0x1022, 0x1537, PSP_NONE},
+ {0x1022, 0x1456, PSP_V1},
+ {0x1022, 0x1468, PSP_NONE},
+ {0x1022, 0x1486, PSP_V2},
+ {0x1022, 0x15DF, PSP_V3},
+ {0x1022, 0x1649, PSP_V2},
+ {0x1022, 0x14CA, PSP_V3},
+ {0x1022, 0x15C7, PSP_NONE}
+};
+
static psp_version_t psp_version;
static struct psp_drtm_interface psp_drtm;
+struct drtm_capability
+{
+ int drtm_enabled;
+ int tsme_enabled;
+ int anti_rollback_status_bit;
+ grub_uint32_t version;
+ grub_uint32_t tmr_alignment;
+ grub_uint32_t tmr_count;
+};
+
+static struct drtm_capability drtm_capability;
+
+static const char *drtm_status_strings[] = {
+ "DRTM_NO_ERROR",
+ "DRTM_NOT_SUPPORTED",
+ "DRTM_LAUNCH_ERROR",
+ "DRTM_TMR_SETUP_FAILED_ERROR",
+ "DRTM_TMR_DESTROY_FAILED_ERROR",
+ "UNDEFINED",
+ "UNDEFINED",
+ "DRTM_GET_TCG_LOGS_FAILED_ERROR",
+ "DRTM_OUT_OF_RESOURCES_ERROR",
+ "DRTM_GENERIC_ERROR",
+ "DRTM_INVALID_SERVICE_ID_ERROR",
+ "DRTM_MEMORY_UNALIGNED_ERROR",
+ "DRTM_MINIMUM_SIZE_ERROR",
+ "DRTM_GET_TMR_DESCRIPTOR_FAILED",
+ "DRTM_EXTEND_OSSL_DIGEST_FAILED",
+ "DRTM_SETUP_NOT_ALLOWED",
+ "DRTM_GET_IVRS_TABLE_FAILED"
+};
+
static grub_err_t init_drtm_interface (grub_addr_t base_addr, psp_version_t
version);
+static void init_drtm_device (grub_pci_device_t dev);
+static int drtm_wait_for_psp_ready (grub_uint32_t *status);
+
+static const char *
+drtm_status_string (grub_uint32_t status)
+{
+ if (status > DRTM_GET_IVRS_TABLE_FAILED)
+ return "UNDEFINED";
+
+ return drtm_status_strings[status];
+}
static void
smn_register_read (grub_uint32_t address, grub_uint32_t *value)
@@ -89,24 +152,117 @@ get_psp_bar_addr (void)
return (grub_uint64_t) pspbaselo;
}
+static const struct pci_psp_device *
+lookup_drtm_device (grub_uint16_t vendor_id, grub_uint16_t dev_id)
+{
+ grub_uint32_t max_psp_devs = sizeof (psp_devs_list) / sizeof
(psp_devs_list[0]);
+ const struct pci_psp_device *psp = NULL;
+ grub_uint32_t i;
+
+ for (i = 0; i < max_psp_devs; i++)
+ {
+ if ((psp_devs_list[i].vendor_id == vendor_id) &&
+ (psp_devs_list[i].dev_id == dev_id))
+ {
+ psp = &psp_devs_list[i];
+ break;
+ }
+ }
+
+ if (psp && psp->version == PSP_NONE)
+ {
+ grub_dprintf ("slaunch", "DRTM: AMD SP device (PCI info: 0x%04x, 0x%04x)
does not have PSP\n",
+ psp->vendor_id, psp->dev_id);
+ psp = NULL;
+ }
+
+ return psp;
+}
+
grub_err_t
grub_psp_discover (void)
{
+ grub_pci_device_t dev;
+ grub_pci_address_t addr;
+ grub_uint16_t vendor_id, dev_id;
+ const struct pci_psp_device *psp = NULL;
grub_uint64_t bar2_addr = 0;
grub_err_t err;
+ for (dev.bus = 0; dev.bus < GRUB_PCI_NUM_BUS; dev.bus++)
+ {
+ for (dev.device = 0; dev.device < GRUB_PCI_NUM_DEVICES; dev.device++)
+ {
+ for (dev.function = 0; dev.function < GRUB_PCI_NUM_FUNCTIONS;
dev.function++)
+ {
+ addr = grub_pci_make_address (dev, 0);
+ vendor_id = grub_pci_read_word (addr);
+ addr = grub_pci_make_address (dev, 2);
+ dev_id = grub_pci_read_word (addr);
+ psp = lookup_drtm_device (vendor_id, dev_id);
+ if (psp)
+ goto psp_found;
+ }
+ }
+ }
+
+ if (!psp)
+ return grub_error (GRUB_ERR_BAD_DEVICE, N_("DRTM: failed to find PSP\n"));
+
+psp_found:
+ init_drtm_device (dev);
+
bar2_addr = get_psp_bar_addr();
if (!bar2_addr)
return grub_error (GRUB_ERR_BAD_DEVICE, N_("DRTM: failed to find PSP\n"));
- err = init_drtm_interface (bar2_addr, PSP_V2);
+ err = init_drtm_interface (bar2_addr, psp->version);
if (err)
return err;
- psp_version = PSP_V2;
+ psp_version = psp->version;
return GRUB_ERR_NONE;
}
+static void
+init_drtm_device (grub_pci_device_t dev)
+{
+ grub_uint16_t pci_cmd;
+ grub_uint8_t pin, lat;
+ grub_pci_address_t pci_cmd_addr, pin_addr, lat_addr;
+
+ /* Enable memory space access for PSP */
+ pci_cmd_addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
+ pci_cmd = grub_pci_read_word (pci_cmd_addr) | 0x2;
+ grub_pci_write_word (pci_cmd_addr, pci_cmd);
+
+ /* Enable PCI interrupts */
+ pin_addr = grub_pci_make_address (dev, GRUB_PCI_REG_IRQ_PIN);
+ pin = grub_pci_read_byte (pin_addr);
+ if (pin)
+ {
+ pci_cmd = grub_pci_read_word (pci_cmd_addr);
+ if (pci_cmd & 0x400)
+ {
+ pci_cmd &= ~0x400;
+ grub_pci_write_word (pci_cmd_addr, pci_cmd);
+ }
+ }
+
+ /* Set PSP at bus master */
+ pci_cmd = grub_pci_read_word (pci_cmd_addr) | 0x4;
+ grub_pci_write_word (pci_cmd_addr, pci_cmd);
+
+ /* Set PCI latency timer */
+ lat_addr = grub_pci_make_address (dev, GRUB_PCI_REG_LAT_TIMER);
+ lat = grub_pci_read_byte (lat_addr);
+ if (lat < 16)
+ {
+ lat = 64;
+ grub_pci_write_byte (lat_addr, lat);
+ }
+}
+
static grub_err_t
init_drtm_interface (grub_addr_t base_addr, psp_version_t version)
{
@@ -131,3 +287,78 @@ grub_psp_version (void)
{
return psp_version;
}
+
+static int
+drtm_wait_for_psp_ready (grub_uint32_t *status)
+{
+ int retry = 5;
+ grub_uint32_t reg_val = 0;
+
+ while (--retry)
+ {
+ reg_val = *psp_drtm.c2pmsg_72;
+
+ if (reg_val & DRTM_MBOX_READY_MASK)
+ break;
+
+ /* TODO: select wait time appropriately */
+ grub_millisleep (100);
+ }
+
+ if (!retry)
+ return 0;
+
+ if (status)
+ *status = reg_val & 0xffff;
+
+ return 1;
+}
+
+/*
+ * For some reason this workaround is necessary to
+ * kickstart the DRTM. Without this step, DRTM does
+ * not return the capability.
+ *
+ * TODO: Check with AMD about why this is necessary.
+ */
+void
+grub_drtm_kick_psp (void)
+{
+ *psp_drtm.c2pmsg_72 = 0;
+
+ (void)drtm_wait_for_psp_ready (NULL);
+}
+
+grub_err_t
+grub_drtm_get_capability (void)
+{
+ grub_uint32_t reg_val = 0;
+ grub_uint32_t status = 0;
+
+ if (!drtm_wait_for_psp_ready (NULL))
+ return grub_error (GRUB_ERR_TIMEOUT, N_("DRTM: %s: PSP not ready to accept
commands\n"), __func__);
+
+ reg_val = (DRTM_CMD_GET_CAPABILITY << DRTM_MBOX_CMD_SHIFT);
+
+ *psp_drtm.c2pmsg_72 = reg_val;
+
+ if (!drtm_wait_for_psp_ready (&status))
+ return grub_error (GRUB_ERR_TIMEOUT, N_("DRTM: %s: failed to get a
response from PSP\n"), __func__);
+
+ if (status != DRTM_NO_ERROR)
+ return grub_error (GRUB_ERR_BAD_DEVICE, N_("DRTM: %s: failed to get PSP
capability - %s\n"),
+ __func__, drtm_status_string (status));
+
+ reg_val = *psp_drtm.c2pmsg_93;
+ drtm_capability.drtm_enabled = (reg_val & 0x1) != 0;
+ drtm_capability.tsme_enabled = (reg_val & 0x2) != 0;
+ drtm_capability.anti_rollback_status_bit = (reg_val & 0x4) != 0;
+
+ drtm_capability.version = *psp_drtm.c2pmsg_94;
+
+ reg_val = *psp_drtm.c2pmsg_95;
+ drtm_capability.tmr_alignment = reg_val & 0x00FFFFFF;
+ drtm_capability.tmr_count = (reg_val & 0xFF000000) >> 24;
+
+ return GRUB_ERR_NONE;
+}
diff --git a/include/grub/i386/psp.h b/include/grub/i386/psp.h
index 8373318ca..915435311 100644
--- a/include/grub/i386/psp.h
+++ b/include/grub/i386/psp.h
@@ -36,7 +36,55 @@
#include <grub/err.h>
#include <grub/types.h>
+#define DRTM_MBOX_READY_MASK 0x80000000
+#define DRTM_MBOX_TMR_INDEX_ID_MASK 0x0F000000
+#define DRTM_MBOX_CMD_MASK 0x00FF0000
+#define DRTM_MBOX_STATUS_MASK 0x0000FFFF
+
+#define DRTM_MBOX_CMD_SHIFT 16
+
+#define DRTM_NO_ERROR 0x00000000
+#define DRTM_NOT_SUPPORTED 0x00000001
+#define DRTM_LAUNCH_ERROR 0x00000002
+#define DRTM_TMR_SETUP_FAILED_ERROR 0x00000003
+#define DRTM_TMR_DESTROY_FAILED_ERROR 0x00000004
+#define DRTM_GET_TCG_LOGS_FAILED_ERROR 0x00000007
+#define DRTM_OUT_OF_RESOURCES_ERROR 0x00000008
+#define DRTM_GENERIC_ERROR 0x00000009
+#define DRTM_INVALID_SERVICE_ID_ERROR 0x0000000A
+#define DRTM_MEMORY_UNALIGNED_ERROR 0x0000000B
+#define DRTM_MINIMUM_SIZE_ERROR 0x0000000C
+#define DRTM_GET_TMR_DESCRIPTOR_FAILED 0x0000000D
+#define DRTM_EXTEND_OSSL_DIGEST_FAILED 0x0000000E
+#define DRTM_SETUP_NOT_ALLOWED 0x0000000F
+#define DRTM_GET_IVRS_TABLE_FAILED 0x00000010
+
+#define DRTM_CMD_GET_CAPABILITY 0x1
+#define DRTM_CMD_TMR_SETUP 0x2
+#define DRTM_CMD_TMR_RELEASE 0x3
+#define DRTM_CMD_LAUNCH 0x4
+#define DRTM_CMD_GET_TCG_LOGS 0x7
+#define DRTM_CMD_TPM_LOCALITY_ACCESS 0x8
+#define DRTM_CMD_GET_TMR_DESCRIPTORS 0x9
+#define DRTM_CMD_ALLOCATE_SHARED_MEMORY 0xA
+#define DRTM_CMD_EXTEND_OSSL_DIGEST 0xB
+#define DRTM_CMD_GET_IVRS_TABLE_INFO 0xC
+
+#define DRTM_TMR_INDEX_0 0
+#define DRTM_TMR_INDEX_1 1
+#define DRTM_TMR_INDEX_2 2
+#define DRTM_TMR_INDEX_3 3
+#define DRTM_TMR_INDEX_4 4
+#define DRTM_TMR_INDEX_5 5
+#define DRTM_TMR_INDEX_6 6
+#define DRTM_TMR_INDEX_7 7
+
+#define DRTM_CMD_READY 0
+#define DRTM_RESPONSE_READY 1
+
extern grub_err_t grub_psp_discover (void);
extern grub_uint16_t grub_psp_version (void);
+extern void grub_drtm_kick_psp (void);
+extern grub_err_t grub_drtm_get_capability (void);
#endif /* __PSP_H__ */
--
2.47.1
- [RFC PATCH 0/7] x86: Trenchboot Secure Launch DRTM for AMD SKINIT (GRUB), Sergii Dmytruk, 2024/12/18
- [RFC PATCH 4/7] slaunch/psp: Setup TMRs to protect RAM from DMA, Sergii Dmytruk, 2024/12/18
- [RFC PATCH 1/7] i386: Extra x86 definitions needed by AMD SKINIT Secure Launch, Sergii Dmytruk, 2024/12/18
- [RFC PATCH 7/7] multiboot2: Support SKINIT Secure Launch, Sergii Dmytruk, 2024/12/18
- [RFC PATCH 5/7] slaunch/skinit: AMD SKINIT Secure Launch core implementation, Sergii Dmytruk, 2024/12/18
- [RFC PATCH 6/7] efi/slaunch: Add AMD Secure Launch support for Linux EFI stub boot, Sergii Dmytruk, 2024/12/18
- [RFC PATCH 2/7] i386: Add PSP discovery code, Sergii Dmytruk, 2024/12/18
- [RFC PATCH 3/7] slaunch/psp: Add core PSP commands and get capability command,
Sergii Dmytruk <=