From: Alec Brown <alec.r.br...@oracle.com> Add various core DRTM commands for the PSP.
Signed-off-by: Alec Brown <alec.r.br...@oracle.com> Signed-off-by: Sergii Dmytruk <sergii.dmyt...@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 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel