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

Reply via email to