[RFC PATCH 0/7] x86: Trenchboot Secure Launch DRTM for AMD SKINIT (GRUB)

1 view
Skip to first unread message

Sergii Dmytruk

unread,
Dec 18, 2024, 2:08:09 PM12/18/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
NOTE: this patch set follows up on Intel TXT DRTM patches that are
currently under review in their 3rd version [v3]; therefore, it is not
standalone! This targets v11 of Linux patches [linux-v11] and
corresponding RFC patch set for AMD SKINIT on top of it [linux-amd-rfc].

The publication of the patches at this point pursues several goals:
- Make anyone tracking upstream aware of the maturity of the support
for AMD SKINIT.
- Collect early feedback on the SKINIT implementation.
- Finally, demonstrate the extensibility of Secure Launch for
incorporating additional platforms.

As the RFC suggest, this series is temporal and will be updated based on
changes made to the initial Secure Launch series for Intel TXT. Review
comments are greatly welcomed and will be worked/addressed, but we would
caution that changes to the Secure Launch series for Intel TXT targeting
Linux and GRUB will take precedence over review comments. Once Intel TXT
Secure Launch series are merged, this series will transition from RFC to
a formally submitted one.

-----

These changes are based on those posted as part of [v1] and [v2], but
also support new [drtm-service] that is available for some CPU families
when PSP/ASP firmware is new enough.

The set of changes can also be viewed on GitHub at [TrenchBoot/grub].

-----

[v1]: https://lists.gnu.org/archive/html/grub-devel/2024-08/msg00088.html
[v2]: https://lists.gnu.org/archive/html/grub-devel/2024-11/msg00000.html
[v3]: https://lists.gnu.org/archive/html/grub-devel/2024-12/msg00028.html
[linux-v11]: https://lkml.org/lkml/2024/9/13/1396
[linux-amd-rfc]: https://lore.kernel.org/lkml/cover.1734008878....@3mdeb.com/
[drtm-service]: https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/user-guides/58453.pdf
[TrenchBoot/grub]: https://github.com/TrenchBoot/grub/compare/tb-2.12-139-v3...tb-amd-2.12-139-rfc-v1

-----

Alec Brown (3):
i386: Add PSP discovery code
slaunch/psp: Add core PSP commands and get capability command
slaunch/psp: Setup TMRs to protect RAM from DMA

Michał Żygowski (1):
multiboot2: Support SKINIT Secure Launch

Ross Philipson (3):
i386: Extra x86 definitions needed by AMD SKINIT Secure Launch
slaunch/skinit: AMD SKINIT Secure Launch core implementation
efi/slaunch: Add AMD Secure Launch support for Linux EFI stub boot

grub-core/Makefile.core.def | 3 +
grub-core/lib/i386/relocator32.S | 6 +
grub-core/loader/efi/dltrampoline.S | 35 +-
grub-core/loader/efi/linux.c | 9 +
grub-core/loader/i386/linux.c | 39 ++-
grub-core/loader/multiboot_mbi2.c | 14 +-
grub-core/loader/slaunch/dlstub.c | 60 +++-
grub-core/loader/slaunch/i386_linux.c | 41 +++
grub-core/loader/slaunch/psp.c | 420 +++++++++++++++++++++++
grub-core/loader/slaunch/skinit.c | 198 +++++++++++
grub-core/loader/slaunch/skl.c | 256 ++++++++++++++
grub-core/loader/slaunch/slaunch.c | 24 +-
grub-core/loader/slaunch/x86_efi_linux.c | 72 ++++
include/grub/i386/cpuid.h | 7 +-
include/grub/i386/msr.h | 6 +
include/grub/i386/pci.h | 1 +
include/grub/i386/psp.h | 91 +++++
include/grub/i386/skinit.h | 69 ++++
include/grub/slaunch.h | 9 +
include/grub/slr_table.h | 16 +
20 files changed, 1351 insertions(+), 25 deletions(-)
create mode 100644 grub-core/loader/slaunch/psp.c
create mode 100644 grub-core/loader/slaunch/skinit.c
create mode 100644 grub-core/loader/slaunch/skl.c
create mode 100644 include/grub/i386/psp.h
create mode 100644 include/grub/i386/skinit.h


base-commit: 5b86bec39d0de1851ddc46d4fc4a80e5a3c52683
prerequisite-patch-id: a4ef62a68c8e0db3ec468dc543ee62a3e6b99a6e
--
2.47.1

Sergii Dmytruk

unread,
Dec 18, 2024, 2:08:12 PM12/18/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Ross Philipson <ross.ph...@oracle.com>

A few MSR/CPUID/PCI x86 definitions added.

Signed-off-by: Ross Philipson <ross.ph...@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
include/grub/i386/cpuid.h | 7 ++++---
include/grub/i386/msr.h | 6 ++++++
include/grub/i386/pci.h | 1 +
3 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/include/grub/i386/cpuid.h b/include/grub/i386/cpuid.h
index e1c45dfc2..36e4ee05e 100644
--- a/include/grub/i386/cpuid.h
+++ b/include/grub/i386/cpuid.h
@@ -28,9 +28,10 @@
#define GRUB_SMX_CPUID_FEATURE (1<<6)

/* AMD */
-#define GRUB_AMD_CPUID_FEATURES 0x80000001
-#define GRUB_SVM_CPUID_FEATURE (1<<2)
-#define GRUB_AMD_CPUID_FUNC 0x8000000a
+#define GRUB_AMD_CPUID_FEATURES 0x80000001
+#define GRUB_SVM_CPUID_FEATURE (1<<2)
+#define GRUB_AMD_CPUID_FUNC 0x8000000a
+#define GRUB_SKINIT_CPUID_FEATURE (1<<12)

extern unsigned char grub_cpuid_has_longmode;
extern unsigned char grub_cpuid_has_pae;
diff --git a/include/grub/i386/msr.h b/include/grub/i386/msr.h
index 9f29c6eb2..726aba9d4 100644
--- a/include/grub/i386/msr.h
+++ b/include/grub/i386/msr.h
@@ -30,6 +30,12 @@
#define GRUB_MSR_X86_APICBASE_ENABLE (1<<11)
#define GRUB_MSR_X86_APICBASE_BASE (0xfffff<<12) /* Mask for APIC base address */

+#define GRUB_MSR_X86_X2APICBASE_ENABLE (1<<10)
+#define GRUB_MSR_X86_X2APICBASE_ICR 0x830
+#define GRUB_MSR_X86_LAPIC_ICR_LO 0x300
+#define GRUB_MSR_X86_ICR_MODE_INIT (5<<8)
+#define GRUB_MSR_X86_ICR_DELIVER_EXCL_SELF (3<<18)
+
#define GRUB_MSR_X86_FEATURE_CONTROL 0x0000003a
#define GRUB_MSR_X86_ENABLE_VMX_IN_SMX (1<<1) /* Enable VMX inside SMX */
#define GRUB_MSR_X86_SENTER_FUNCTIONS (0x7f<<8) /* Bitmap of SENTER function enables */
diff --git a/include/grub/i386/pci.h b/include/grub/i386/pci.h
index dffeb5695..952e8bcca 100644
--- a/include/grub/i386/pci.h
+++ b/include/grub/i386/pci.h
@@ -27,6 +27,7 @@
#define GRUB_PCI_DATA_REG 0xcfc
#define GRUB_PCI_NUM_BUS 256
#define GRUB_PCI_NUM_DEVICES 32
+#define GRUB_PCI_NUM_FUNCTIONS 8

static inline grub_uint32_t
grub_pci_read (grub_pci_address_t addr)
--
2.47.1

Sergii Dmytruk

unread,
Dec 18, 2024, 2:08:15 PM12/18/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Alec Brown <alec.r...@oracle.com>

Add base code for PSP discovery in grub.

Signed-off-by: Alec Brown <alec.r...@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
grub-core/Makefile.core.def | 1 +
grub-core/loader/slaunch/psp.c | 133 +++++++++++++++++++++++++++++++++
include/grub/i386/psp.h | 42 +++++++++++
3 files changed, 176 insertions(+)
create mode 100644 grub-core/loader/slaunch/psp.c
create mode 100644 include/grub/i386/psp.h

diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index aba480842..dabf8fb22 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1883,6 +1883,7 @@ module = {
x86 = loader/slaunch/acmod.c;
x86 = loader/slaunch/verify.c;
x86 = loader/slaunch/i386_linux.c;
+ x86 = loader/slaunch/psp.c;
x86 = loader/slaunch/dlstub.c;
x86 = loader/efi/dltrampoline.S;
x86_64_efi = loader/slaunch/x86_efi_linux.c;
diff --git a/grub-core/loader/slaunch/psp.c b/grub-core/loader/slaunch/psp.c
new file mode 100644
index 000000000..3459f7e34
--- /dev/null
+++ b/grub-core/loader/slaunch/psp.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2024, Oracle and/or its affiliates.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/err.h>
+#include <grub/pci.h>
+#include <grub/i386/pci.h>
+#include <grub/i386/psp.h>
+
+struct psp_drtm_interface
+{
+ volatile grub_uint32_t *c2pmsg_72;
+ volatile grub_uint32_t *c2pmsg_93;
+ volatile grub_uint32_t *c2pmsg_94;
+ volatile grub_uint32_t *c2pmsg_95;
+};
+
+typedef enum
+{
+ PSP_NONE = 0,
+ PSP_V1,
+ PSP_V2,
+ PSP_V3
+} psp_version_t;
+
+static psp_version_t psp_version;
+static struct psp_drtm_interface psp_drtm;
+
+static grub_err_t init_drtm_interface (grub_addr_t base_addr, psp_version_t version);
+
+static void
+smn_register_read (grub_uint32_t address, grub_uint32_t *value)
+{
+ grub_pci_device_t dev = {0, 0, 0};
+ grub_pci_address_t addr;
+ grub_uint32_t val;
+
+ val = address;
+ addr = grub_pci_make_address (dev, 0xb8);
+ grub_pci_write (addr, val);
+ addr = grub_pci_make_address (dev, 0xbc);
+ val = grub_pci_read (addr);
+ *value = val;
+}
+
+#define IOHC0NBCFG_SMNBASE 0x13b00000
+#define PSP_BASE_ADDR_LO_SMN_ADDRESS (IOHC0NBCFG_SMNBASE + 0x102e0)
+
+static grub_uint64_t
+get_psp_bar_addr (void)
+{
+ grub_uint32_t pspbaselo;
+
+ pspbaselo = 0;
+ smn_register_read (PSP_BASE_ADDR_LO_SMN_ADDRESS, &pspbaselo);
+
+ /* Mask out the lower bits */
+ pspbaselo &= 0xfff00000;
+ return (grub_uint64_t) pspbaselo;
+}
+
+grub_err_t
+grub_psp_discover (void)
+{
+ grub_uint64_t bar2_addr = 0;
+ grub_err_t err;
+
+ 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);
+ if (err)
+ return err;
+
+ psp_version = PSP_V2;
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+init_drtm_interface (grub_addr_t base_addr, psp_version_t version)
+{
+ switch (version)
+ {
+ case PSP_V2:
+ case PSP_V3:
+ psp_drtm.c2pmsg_72 = (volatile grub_uint32_t *)(base_addr + 0x10a20);
+ psp_drtm.c2pmsg_93 = (volatile grub_uint32_t *)(base_addr + 0x10a74);
+ psp_drtm.c2pmsg_94 = (volatile grub_uint32_t *)(base_addr + 0x10a78);
+ psp_drtm.c2pmsg_95 = (volatile grub_uint32_t *)(base_addr + 0x10a7c);
+ break;
+ default:
+ return grub_error (GRUB_ERR_BAD_DEVICE, N_("DRTM: Unrecognized PSP version %d\n"), version);
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+grub_uint16_t
+grub_psp_version (void)
+{
+ return psp_version;
+}
diff --git a/include/grub/i386/psp.h b/include/grub/i386/psp.h
new file mode 100644
index 000000000..8373318ca
--- /dev/null
+++ b/include/grub/i386/psp.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2024, Oracle and/or its affiliates.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of the Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __PSP_H__
+#define __PSP_H__
+
+#include <grub/err.h>
+#include <grub/types.h>
+
+extern grub_err_t grub_psp_discover (void);
+extern grub_uint16_t grub_psp_version (void);
+
+#endif /* __PSP_H__ */
--
2.47.1

Sergii Dmytruk

unread,
Dec 18, 2024, 2:08:17 PM12/18/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Alec Brown <alec.r...@oracle.com>

Add various core DRTM commands for the PSP.

Signed-off-by: Alec Brown <alec.r...@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii....@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);

Sergii Dmytruk

unread,
Dec 18, 2024, 2:08:20 PM12/18/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Alec Brown <alec.r...@oracle.com>

TMRs are setup and used to protect ranges of memory from outside
access like DMA. Setting them up to cover all memory protects from
DMA during the establishment of the DRTM environment.

Signed-off-by: Alec Brown <alec.r...@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
grub-core/loader/slaunch/psp.c | 56 ++++++++++++++++++++++++++++++++++
include/grub/i386/psp.h | 1 +
2 files changed, 57 insertions(+)

diff --git a/grub-core/loader/slaunch/psp.c b/grub-core/loader/slaunch/psp.c
index 2bbb4c685..553e53ed4 100644
--- a/grub-core/loader/slaunch/psp.c
+++ b/grub-core/loader/slaunch/psp.c
@@ -36,6 +36,9 @@
#include <grub/mm.h>
#include <grub/time.h>
#include <grub/pci.h>
+#include <grub/efi/efi.h>
+#include <grub/efi/api.h>
+#include <grub/i386/linux.h>
#include <grub/i386/pci.h>
#include <grub/i386/psp.h>

@@ -362,3 +365,56 @@ grub_drtm_get_capability (void)

return GRUB_ERR_NONE;
}
+
+/**
+ * Setup Trusted Memory Region (TMR). The PSP supports only
+ * 1 TMR - as such all of the sysmem region is covered in
+ * a single TMR.
+ *
+ * Walk the E820 MB2 memory map table to figure out the end
+ * of the memory addresses. Setup the TMR to cover address
+ * ranges from 0x0 to the end calculated during the walk.
+ */
+int
+grub_drtm_setup_tmrs (grub_uint64_t tmr_end)
+{
+ grub_uint64_t tmr_count = 0;
+ grub_uint64_t rem = 0;
+ grub_uint32_t status = 0;
+
+ tmr_count = grub_divmod64 (tmr_end, drtm_capability.tmr_alignment, &rem);
+ if (rem != 0)
+ tmr_count++;
+
+ if (tmr_count > GRUB_UINT_MAX)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, N_("DRTM: %s: memory region bigger than TMR\n"), __func__);
+ return -1;
+ }
+
+ /*
+ * Setup TMR for address range 0x0 to tmr_end. Size is in
+ * multiples of tmr_alignment.
+ */
+ *psp_drtm.c2pmsg_93 = (grub_uint32_t)tmr_count;
+ *psp_drtm.c2pmsg_94 = 0;
+ *psp_drtm.c2pmsg_95 = 0;
+
+ *psp_drtm.c2pmsg_72 = (DRTM_TMR_INDEX_0 << 24) |
+ (DRTM_CMD_TMR_SETUP << DRTM_MBOX_CMD_SHIFT);
+
+ if (!drtm_wait_for_psp_ready (&status))
+ {
+ grub_error (GRUB_ERR_TIMEOUT, N_("DRTM: %s: failed to get a response from PSP\n"), __func__);
+ return -1;
+ }
+
+ if (status != DRTM_NO_ERROR)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, N_("DRTM: %s: failed to setup TMRs - %s\n"),
+ __func__, drtm_status_string (status));
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/include/grub/i386/psp.h b/include/grub/i386/psp.h
index 915435311..4df31735d 100644
--- a/include/grub/i386/psp.h
+++ b/include/grub/i386/psp.h
@@ -86,5 +86,6 @@ 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);
+extern int grub_drtm_setup_tmrs (grub_uint64_t tmr_end);

Sergii Dmytruk

unread,
Dec 18, 2024, 2:08:23 PM12/18/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Ross Philipson <ross.ph...@oracle.com>

Add core implementation for AMD SKINIT Secure Launch in GRUB based on
Linux legacy boot protocol.

Signed-off-by: Ross Philipson <ross.ph...@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
grub-core/Makefile.core.def | 2 +
grub-core/lib/i386/relocator32.S | 6 +
grub-core/loader/i386/linux.c | 39 ++++-
grub-core/loader/slaunch/dlstub.c | 56 ++++++-
grub-core/loader/slaunch/i386_linux.c | 41 +++++
grub-core/loader/slaunch/skinit.c | 184 +++++++++++++++++++++
grub-core/loader/slaunch/skl.c | 223 ++++++++++++++++++++++++++
grub-core/loader/slaunch/slaunch.c | 24 ++-
include/grub/i386/skinit.h | 69 ++++++++
include/grub/slaunch.h | 7 +
include/grub/slr_table.h | 16 ++
11 files changed, 654 insertions(+), 13 deletions(-)
create mode 100644 grub-core/loader/slaunch/skinit.c
create mode 100644 grub-core/loader/slaunch/skl.c
create mode 100644 include/grub/i386/skinit.h

diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index dabf8fb22..ac48cd8aa 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1884,6 +1884,8 @@ module = {
x86 = loader/slaunch/verify.c;
x86 = loader/slaunch/i386_linux.c;
x86 = loader/slaunch/psp.c;
+ x86 = loader/slaunch/skinit.c;
+ x86 = loader/slaunch/skl.c;
x86 = loader/slaunch/dlstub.c;
x86 = loader/efi/dltrampoline.S;
x86_64_efi = loader/slaunch/x86_efi_linux.c;
diff --git a/grub-core/lib/i386/relocator32.S b/grub-core/lib/i386/relocator32.S
index 25f162b0e..837d2e70f 100644
--- a/grub-core/lib/i386/relocator32.S
+++ b/grub-core/lib/i386/relocator32.S
@@ -115,6 +115,9 @@ VARIABLE(grub_relocator32_edx)
cmpl $SLP_INTEL_TXT, %edi
je LOCAL(intel_txt)

+ cmpl $SLP_AMD_SKINIT, %edi
+ je LOCAL(amd_skinit)
+
.byte 0xea
VARIABLE(grub_relocator32_eip)
.long 0
@@ -123,6 +126,9 @@ VARIABLE(grub_relocator32_eip)
LOCAL(intel_txt):
getsec

+LOCAL(amd_skinit):
+ skinit
+
/* GDT. Copied from loader/i386/linux.c. */
.p2align 4
LOCAL(gdt):
diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
index 2a74881fb..f5b13c24e 100644
--- a/grub-core/loader/i386/linux.c
+++ b/grub-core/loader/i386/linux.c
@@ -38,6 +38,7 @@
#include <grub/lib/cmdline.h>
#include <grub/i386/mmio.h>
#include <grub/i386/txt.h>
+#include <grub/i386/skinit.h>
#include <grub/linux.h>
#include <grub/machine/kernel.h>
#include <grub/safemath.h>
@@ -228,6 +229,13 @@ allocate_pages (grub_size_t prot_size, grub_size_t *align,
if (err)
goto fail;
}
+ else if (grub_slaunch_platform_type () == SLP_AMD_SKINIT)
+ {
+ err = grub_sl_skinit_setup_linux (&slparams, relocator, total_size, prot_file_size,
+ prot_mode_mem, prot_mode_target);
+ if (err)
+ goto fail;
+ }

grub_dprintf ("linux", "prot_mode_mem = %p, prot_mode_target = %lx, prot_size = %x\n",
prot_mode_mem, (unsigned long) prot_mode_target,
@@ -660,16 +668,39 @@ grub_linux_boot (void)
}
#endif

- if (grub_slaunch_platform_type () == SLP_INTEL_TXT)
+ if (grub_slaunch_platform_type () == SLP_AMD_SKINIT)
+ {
+ /*
+ * AMD SKL final setup may relocate the SKL module. It is also what sets the SLRT and DCE
+ * values in slparams so this must be done before final setup and launch below.
+ */
+ err = grub_skl_setup_module (&slparams);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
+ if (grub_slaunch_platform_type () != SLP_NONE)
{
struct grub_slr_table *slrt = (struct grub_slr_table *)slparams.slr_table_mem;
struct grub_slr_entry_dl_info *dlinfo;

+ slparams.efi_memmap_mem = efi_mmap_buf;
slparams.platform_type = grub_slaunch_platform_type();

- err = grub_txt_boot_prepare (&slparams);
- if (err != GRUB_ERR_NONE)
- return err;
+ if (grub_slaunch_platform_type () == SLP_INTEL_TXT)
+ {
+ err = grub_txt_boot_prepare (&slparams);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+ else if (grub_slaunch_platform_type () == SLP_AMD_SKINIT)
+ {
+ err = grub_skl_prepare_bootloader_data (&slparams);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+ else
+ return GRUB_ERR_BAD_DEVICE;

dlinfo = grub_slr_next_entry_by_tag (slrt, NULL, GRUB_SLR_ENTRY_DL_INFO);
dl_entry ((grub_uint64_t)(grub_addr_t)&dlinfo->bl_context);
diff --git a/grub-core/loader/slaunch/dlstub.c b/grub-core/loader/slaunch/dlstub.c
index 2cdbdd886..fc1afed33 100644
--- a/grub-core/loader/slaunch/dlstub.c
+++ b/grub-core/loader/slaunch/dlstub.c
@@ -22,12 +22,16 @@
#include <grub/misc.h>
#include <grub/types.h>
#include <grub/dl.h>
+#include <grub/time.h>
#include <grub/slr_table.h>
#include <grub/slaunch.h>
#include <grub/cpu/relocator.h>
#include <grub/i386/msr.h>
#include <grub/i386/mmio.h>
+#include <grub/i386/psp.h>
+#include <grub/i386/tpm.h>
#include <grub/i386/txt.h>
+#include <grub/i386/skinit.h>

GRUB_MOD_LICENSE ("GPLv3+");

@@ -42,11 +46,12 @@ void dl_entry (grub_uint64_t dl_ctx)

state.edi = slparams->platform_type;

+ /* This is done on both Intel and AMD platforms */
+ if (slparams->boot_type == GRUB_SL_BOOT_TYPE_EFI)
+ grub_update_slrt_policy (slparams);
+
if (slparams->platform_type == SLP_INTEL_TXT)
{
- if (slparams->boot_type == GRUB_SL_BOOT_TYPE_EFI)
- grub_update_slrt_policy (slparams);
-
err = grub_set_mtrrs_for_acmod ((void *)(grub_addr_t)slparams->dce_base);
if (err)
{
@@ -61,6 +66,33 @@ void dl_entry (grub_uint64_t dl_ctx)
return;
}
}
+ else if (slparams->platform_type == SLP_AMD_SKINIT)
+ {
+ grub_skl_link_amd_info (slparams);
+
+ err = grub_psp_discover ();
+ if (err == GRUB_ERR_NONE)
+ {
+ err = grub_skinit_psp_memory_protect (slparams);
+ if (err != GRUB_ERR_NONE)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, N_("setup PSP TMR memory protection failed"));
+ return;
+ }
+ }
+ else
+ grub_tpm_relinquish_locality (0);
+
+ err = grub_skinit_prepare_cpu ();
+ if ( err )
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, N_("setup CPU for SKINIT failed"));
+ return;
+ }
+
+ /* Have to do this after EBS or things blow up */
+ grub_skinit_send_init_ipi_shorthand ();
+ }
else
{
grub_error (GRUB_ERR_BUG, N_("unknown dynamic launch platform: %d"), slparams->platform_type);
@@ -75,11 +107,19 @@ void dl_entry (grub_uint64_t dl_ctx)

if (slparams->boot_type == GRUB_SL_BOOT_TYPE_LINUX || slparams->boot_type == GRUB_SL_BOOT_TYPE_MB2)
{
- /* Configure relocator GETSEC[SENTER] call. */
- state.eax = GRUB_SMX_LEAF_SENTER;
- state.ebx = slparams->dce_base;
- state.ecx = slparams->dce_size;
- state.edx = 0;
+ if (slparams->platform_type == SLP_INTEL_TXT)
+ {
+ /* Configure relocator GETSEC[SENTER] call. */
+ state.eax = GRUB_SMX_LEAF_SENTER;
+ state.ebx = slparams->dce_base;
+ state.ecx = slparams->dce_size;
+ state.edx = 0;
+ }
+ else if (slparams->platform_type == SLP_AMD_SKINIT)
+ {
+ state.eax = slparams->dce_base;
+ }
+
grub_relocator32_boot (slparams->relocator, state, 0);
}
else if (slparams->boot_type == GRUB_SL_BOOT_TYPE_EFI)
diff --git a/grub-core/loader/slaunch/i386_linux.c b/grub-core/loader/slaunch/i386_linux.c
index 770888f63..2a830c0b3 100644
--- a/grub-core/loader/slaunch/i386_linux.c
+++ b/grub-core/loader/slaunch/i386_linux.c
@@ -218,3 +218,44 @@ grub_sl_txt_setup_linux (struct grub_slaunch_params *slparams, struct grub_reloc
fail:
return grub_errno;
}
+
+grub_err_t
+grub_sl_skinit_setup_linux (struct grub_slaunch_params *slparams, struct grub_relocator *relocator,
+ grub_size_t total_size, grub_size_t prot_file_size,
+ void *prot_mode_mem, grub_addr_t prot_mode_target)
+{
+ grub_relocator_chunk_t ch;
+
+ slparams->boot_type = GRUB_SL_BOOT_TYPE_LINUX;
+ slparams->relocator = relocator;
+
+ /* Zero out memory to get stable MLE measurements. */
+ grub_memset (prot_mode_mem, 0, total_size);
+
+ slparams->mle_mem = prot_mode_mem;
+ slparams->mle_start = prot_mode_target;
+ slparams->mle_size = prot_file_size;
+
+ /* Less to do on AMD. Just need to setup an event log buffer and some values */
+ if (grub_relocator_alloc_chunk_align (relocator, &ch, 0x1000000,
+ 0xffffffff - GRUB_SLAUNCH_TPM_EVT_LOG_SIZE,
+ GRUB_SLAUNCH_TPM_EVT_LOG_SIZE, GRUB_PAGE_SIZE,
+ GRUB_RELOCATOR_PREFERENCE_NONE, 1))
+ goto fail;
+
+ slparams->tpm_evt_log_base = get_physical_target_address (ch);
+ slparams->tpm_evt_log_size = GRUB_SLAUNCH_TPM_EVT_LOG_SIZE;
+
+ grub_memset (get_virtual_current_address (ch), 0, slparams->tpm_evt_log_size);
+
+ grub_dprintf ("linux", "tpm_evt_log_base = %lx, tpm_evt_log_size = %x\n",
+ (unsigned long) slparams->tpm_evt_log_base,
+ (unsigned) slparams->tpm_evt_log_size);
+
+ /* The SLRT is located in the SKL image and the wake block is not needed on AMD */
+
+ return GRUB_ERR_NONE;
+
+fail:
+ return grub_errno;
+}
diff --git a/grub-core/loader/slaunch/skinit.c b/grub-core/loader/slaunch/skinit.c
new file mode 100644
index 000000000..988b784b9
--- /dev/null
+++ b/grub-core/loader/slaunch/skinit.c
@@ -0,0 +1,184 @@
+#include <grub/loader.h>
+#include <grub/memory.h>
+#include <grub/normal.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/time.h>
+#include <grub/types.h>
+#include <grub/dl.h>
+#include <grub/slr_table.h>
+#include <grub/slaunch.h>
+#include <grub/efi/efi.h>
+#include <grub/i386/msr.h>
+#include <grub/i386/mmio.h>
+#include <grub/i386/crfr.h>
+#include <grub/i386/linux.h>
+#include <grub/i386/psp.h>
+#include <grub/i386/skinit.h>
+
+grub_err_t
+grub_skinit_is_supported (void)
+{
+ grub_uint32_t eax, ebx, ecx, edx;
+
+ grub_cpuid (GRUB_AMD_CPUID_FEATURES, eax, ebx, ecx, edx);
+
+ if (ecx & GRUB_SKINIT_CPUID_FEATURE)
+ {
+ grub_dprintf ("slaunch", "SKINIT CPU and all needed capabilities present\n");
+ return GRUB_ERR_NONE;
+ }
+ return grub_error (GRUB_ERR_BAD_DEVICE, N_("CPU does not support SKINIT"));
+}
+
+grub_err_t
+grub_skinit_prepare_cpu (void)
+{
+ unsigned long eflags, cr0;
+ grub_uint64_t mcg_cap, mcg_stat;
+ grub_uint32_t i;
+
+ cr0 = grub_read_control_register (GRUB_CR0);
+
+ /* Cache must be enabled (CR0.CD = CR0.NW = 0). */
+ if (!(cr0 & GRUB_CR0_X86_CD))
+ cr0 &= ~GRUB_CR0_X86_CD;
+ if (cr0 & GRUB_CR0_X86_NW)
+ cr0 &= ~GRUB_CR0_X86_NW;
+
+ /*
+ * Native FPU error reporting must be enable for proper
+ * iteraction behavior
+ */
+ if (!(cr0 & GRUB_CR0_X86_NE))
+ cr0 |= GRUB_CR0_X86_NE;
+
+ grub_write_control_register (GRUB_CR0, cr0);
+
+ /* Cannot be in virtual-8086 mode (EFLAGS.VM=0) */
+ eflags = grub_read_flags_register ();
+ if (eflags & GRUB_EFLAGS_X86_VM)
+ grub_write_flags_register (eflags & ~GRUB_EFLAGS_X86_VM);
+
+ /*
+ * Verify all machine check status registers are clear (unless
+ * support preserving them)
+ */
+
+ /* No machine check in progress (IA32_MCG_STATUS.MCIP=1) */
+ mcg_stat = grub_rdmsr (GRUB_MSR_X86_MCG_STATUS);
+ if (mcg_stat & 0x04)
+ return -1;
+
+ /* Check if all machine check regs are clear */
+ mcg_cap = grub_rdmsr (GRUB_MSR_X86_MCG_CAP);
+ for (i = 0; i < (mcg_cap & GRUB_MSR_MCG_BANKCNT_MASK); i++)
+ {
+ mcg_stat = grub_rdmsr (GRUB_MSR_X86_MC0_STATUS + i * 4);
+ if (mcg_stat & (1ULL << 63))
+ return grub_error (GRUB_ERR_BAD_DEVICE, N_("secure launch MCG[%u] = %llx ERROR"),
+ i, (unsigned long long)mcg_stat);
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_skinit_psp_memory_protect (struct grub_slaunch_params *slparams)
+{
+ struct linux_kernel_params *boot_params = slparams->boot_params;
+ grub_efi_memory_descriptor_t *memory_map_end;
+ grub_efi_memory_descriptor_t *desc;
+ struct grub_efi_info *efi_info;
+ grub_uint64_t efi_memmap, tmr_end = 0;
+ grub_err_t err;
+
+ /* A bit of work to extract the v2.08 EFI info from the linux params */
+ efi_info = (struct grub_efi_info *)((grub_uint8_t *)&(boot_params->v0208)
+ + 2*sizeof(grub_uint32_t));
+
+ /*
+ * On legacy Linux boots, the relocator is used to map the EFI memory map buffer
+ * and return a virtual address to use. This virtual address is stashed in slparams.
+ */
+ efi_memmap = (grub_uint64_t)(grub_addr_t)slparams->efi_memmap_mem;
+
+ desc = (grub_efi_memory_descriptor_t *)(grub_addr_t) efi_memmap;
+ memory_map_end = (grub_efi_memory_descriptor_t *)(grub_addr_t) (efi_memmap + efi_info->efi_mmap_size);
+ for (; desc < memory_map_end; desc = (grub_efi_memory_descriptor_t *) ((char *) desc + efi_info->efi_mem_desc_size))
+ {
+ tmr_end = desc->physical_start + (desc->num_pages << 12);
+ }
+
+ grub_drtm_kick_psp ();
+
+ err = grub_drtm_get_capability ();
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ err = grub_drtm_setup_tmrs (tmr_end);
+ if ( err != GRUB_ERR_NONE)
+ return err;
+
+ return GRUB_ERR_NONE;
+}
+
+/* Broadcast INIT to all APs except self */
+void
+grub_skinit_send_init_ipi_shorthand (void)
+{
+ grub_addr_t icr_reg;
+ grub_uint32_t apic_base = (grub_uint32_t) grub_rdmsr (GRUB_MSR_X86_APICBASE);
+
+ /* accessing the ICR depends on the APIC mode */
+ if (apic_base & GRUB_MSR_X86_X2APICBASE_ENABLE)
+ {
+ grub_mb ();
+
+ /* access ICR through MSR */
+ grub_wrmsr (GRUB_MSR_X86_X2APICBASE_ICR, (GRUB_MSR_X86_ICR_DELIVER_EXCL_SELF|GRUB_MSR_X86_ICR_MODE_INIT));
+ }
+ else
+ {
+ /* mask off low order bits to get base address */
+ apic_base &= GRUB_MSR_X86_APICBASE_BASE;
+ /* access ICR through MMIO */
+ icr_reg = apic_base + GRUB_MSR_X86_LAPIC_ICR_LO;
+
+ grub_write32 ((GRUB_MSR_X86_ICR_DELIVER_EXCL_SELF|GRUB_MSR_X86_ICR_MODE_INIT), icr_reg);
+ }
+
+ grub_millisleep (1000);
+}
diff --git a/grub-core/loader/slaunch/skl.c b/grub-core/loader/slaunch/skl.c
new file mode 100644
index 000000000..76ee5cf74
--- /dev/null
+++ b/grub-core/loader/slaunch/skl.c
@@ -0,0 +1,223 @@
+#include <grub/err.h>
+#include <grub/loader.h>
+#include <grub/relocator.h>
+#include <grub/slaunch.h>
+#include <grub/slr_table.h>
+#include <grub/i386/memory.h>
+#include <grub/i386/linux.h>
+#include <grub/i386/psp.h>
+#include <grub/i386/skinit.h>
+
+#define SLRT_SIZE GRUB_PAGE_SIZE
+
+#define SLB_MIN_ALIGNMENT 0x10000
+#define SLB_SIZE 0x10000
+
+static struct grub_skl_info skl_info = {
+ .uuid = {
+ 0x78, 0xf1, 0x26, 0x8e, 0x04, 0x92, 0x11, 0xe9,
+ 0x83, 0x2a, 0xc8, 0x5b, 0x76, 0xc4, 0xcc, 0x02,
+ },
+ .version = GRUB_SKL_VERSION,
+ .msb_key_algo = 0x14,
+ .msb_key_hash = { 0 },
+};
+
+static struct grub_sl_header *skl_module = NULL;
+static grub_uint32_t skl_size = 0;
+
+int
+grub_skl_set_module (const void *skl_base, grub_uint32_t size)
+{
+ struct grub_skl_info *info;
+ struct grub_sl_header *module = (struct grub_sl_header *) skl_base;
+
+ /* We need unused space after the module to fit SLRT there. */
+ const grub_uint32_t max_size = SLB_SIZE - SLRT_SIZE;
+
+ if (size > max_size)
+ {
+ grub_dprintf ("slaunch", "Possible SKL module is too large: %u > %u\n",
+ size, max_size);
+ return 0;
+ }
+
+ if (module->length > size)
+ {
+ grub_dprintf ("slaunch",
+ "Possible SKL module has wrong measured size: %u > %u\n",
+ module->length, size);
+ return 0;
+ }
+
+ if (module->skl_entry_point >= module->length)
+ {
+ grub_dprintf ("slaunch",
+ "Possible SKL module doesn't measure its entry: %u >= %u\n",
+ module->skl_entry_point, module->length);
+ return 0;
+ }
+
+ if (module->skl_info_offset > module->length - sizeof (info->uuid))
+ {
+ grub_dprintf ("slaunch",
+ "Possible SKL module doesn't measure info: %u > %u\n",
+ module->skl_info_offset,
+ module->length - sizeof (info->uuid));
+ return 0;
+ }
+
+ if ((unsigned)SLB_SIZE - module->bootloader_data_offset < SLRT_SIZE)
+ {
+ grub_dprintf ("slaunch",
+ "Possible SKL module has not enough space for SLRT: %u < %lu\n",
+ SLB_SIZE - module->bootloader_data_offset, SLRT_SIZE);
+ return 0;
+ }
+
+ if (module->length > module->bootloader_data_offset)
+ {
+ grub_dprintf ("slaunch",
+ "Possible SKL module measures bootloader data: %u (measured prefix) > %u (data offset)\n",
+ module->length, module->bootloader_data_offset);
+ return 0;
+ }
+
+ info = (struct grub_skl_info *) ((grub_uint8_t *) module + module->skl_info_offset);
+ if (info->version != GRUB_SKL_VERSION)
+ {
+ grub_dprintf ("slaunch", "Possible SKL module has unexpected version\n");
+ return 0;
+ }
+
+ if (grub_memcmp (info->uuid, skl_info.uuid, 16))
+ {
+ grub_dprintf ("slaunch", "Possible SKL module has unexpected UUID\n");
+ return 0;
+ }
+
+ skl_module = module;
+ skl_size = size;
+ return 1;
+}
+
+grub_err_t
+grub_skl_setup_module (struct grub_slaunch_params *slparams)
+{
+ grub_relocator_chunk_t ch;
+ grub_phys_addr_t p_addr;
+ grub_uint8_t *v_addr;
+ grub_err_t err;
+
+ err = grub_relocator_alloc_chunk_align (slparams->relocator, &ch,
+ 0, UP_TO_TOP32(SLB_SIZE), SLB_SIZE,
+ SLB_MIN_ALIGNMENT,
+ GRUB_RELOCATOR_PREFERENCE_HIGH,
+ 1);
+
+ if (err != GRUB_ERR_NONE)
+ return grub_error (err, N_("failed to allocate SLB"));
+
+ v_addr = get_virtual_current_address (ch);
+ p_addr = get_physical_target_address (ch);
+
+ grub_memcpy (v_addr, skl_module, skl_size);
+ skl_module = (struct grub_sl_header *) v_addr;
+
+ /* Once relocated, setup the DCE info in slparams */
+ slparams->dce_size = skl_size;
+ slparams->dce_base = (grub_uint64_t)p_addr;
+
+ /* The SLRT resides in the relocated SKL bootloader_data section, set the values here */
+ slparams->slr_table_base = (grub_uint64_t)p_addr + skl_module->bootloader_data_offset;
+ slparams->slr_table_size = SLB_SIZE - skl_module->bootloader_data_offset;
+ slparams->slr_table_mem = v_addr + skl_module->bootloader_data_offset;
+
+ return GRUB_ERR_NONE;
+}
+
+void
+grub_skl_link_amd_info (struct grub_slaunch_params *slparams)
+{
+ struct grub_slr_entry_amd_info *amd_info;
+
+ amd_info = grub_slr_next_entry_by_tag ((struct grub_slr_table *)(grub_addr_t) slparams->slr_table_base,
+ NULL,
+ GRUB_SLR_ENTRY_AMD_INFO);
+
+ amd_info->next = slparams->boot_params->setup_data;
+ slparams->boot_params->setup_data = (grub_uint64_t)(grub_addr_t)amd_info + sizeof (struct grub_slr_entry_hdr);
+}
+
+grub_err_t
+grub_skl_prepare_bootloader_data (struct grub_slaunch_params *slparams)
+{
+ struct grub_slr_table *slrt = (struct grub_slr_table *)slparams->slr_table_mem;
+ struct grub_slr_entry_amd_info slr_amd_info_staging = {0};
+ grub_err_t err;
+
+ /* Setup the staging for AMD platform specific entry */
+ slr_amd_info_staging.hdr.tag = GRUB_SLR_ENTRY_AMD_INFO;
+ slr_amd_info_staging.hdr.size = sizeof (struct grub_slr_entry_amd_info);
+ slr_amd_info_staging.type = GRUB_SETUP_SECURE_LAUNCH;
+ slr_amd_info_staging.len = sizeof (struct grub_slr_entry_amd_info);
+ slr_amd_info_staging.slrt_size = slparams->slr_table_size;
+ slr_amd_info_staging.slrt_base = slparams->slr_table_base;
+ slr_amd_info_staging.boot_params_base = slparams->boot_params_base;
+ slr_amd_info_staging.psp_version = grub_psp_version();
+
+ /* Setup the generic bits of the SLRT */
+ grub_slr_init_table (slrt, GRUB_SLR_AMD_SKINIT, slparams->slr_table_size);
+
+ /* Prepare SLR table staging area */
+ grub_init_slrt_storage ();
+
+ /* Create the SLR security policy */
+ err = grub_setup_slrt_policy (slparams, NULL);
+ if (err != GRUB_ERR_NONE)
+ return grub_error (err, N_("failed to build SLR policy"));
+
+ /* Setup DL entry point, DCE and DLME information */
+ grub_setup_slrt_dl_info (slparams);
+
+ /* Setup the DRTM log info */
+ grub_setup_slrt_log_info (slparams);
+
+ /* Final move of staging information into the actual SLRT */
+ grub_setup_slr_table (slparams, (struct grub_slr_entry_hdr *)&slr_amd_info_staging);
+
+ return GRUB_ERR_NONE;
+}
diff --git a/grub-core/loader/slaunch/slaunch.c b/grub-core/loader/slaunch/slaunch.c
index 8079bae7a..15a2b5a09 100644
--- a/grub-core/loader/slaunch/slaunch.c
+++ b/grub-core/loader/slaunch/slaunch.c
@@ -28,6 +28,7 @@
#include <grub/i386/msr.h>
#include <grub/i386/mmio.h>
#include <grub/i386/txt.h>
+#include <grub/i386/skinit.h>

GRUB_MOD_LICENSE ("GPLv3+");

@@ -75,6 +76,15 @@ grub_cmd_slaunch (grub_command_t cmd __attribute__ ((unused)),

slp = SLP_INTEL_TXT;
}
+ else if (!grub_memcmp (manufacturer, "AuthenticAMD", 12))
+ {
+ err = grub_skinit_is_supported ();
+
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ slp = SLP_AMD_SKINIT;
+ }
else
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("CPU is unsupported"));

@@ -95,7 +105,7 @@ grub_cmd_slaunch_module (grub_command_t cmd __attribute__ ((unused)),
if (slp == SLP_NONE)
return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("secure launch not enabled"));

- if (slp > SLP_INTEL_TXT)
+ if (slp > SLP_AMD_SKINIT)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
N_("unknown secure launch platform type: %d"), slp);

@@ -141,6 +151,14 @@ grub_cmd_slaunch_module (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
}
+ else if (slp == SLP_AMD_SKINIT)
+ {
+ if (!grub_skl_set_module (new_module, size))
+ {
+ grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("SKL module isn't correct"));
+ goto fail;
+ }
+ }

grub_file_close (file);

@@ -172,6 +190,10 @@ grub_cmd_slaunch_state (grub_command_t cmd __attribute__ ((unused)),
grub_printf ("Secure launcher: Intel TXT\n");
grub_txt_state_show ();
}
+ else if (slp == SLP_AMD_SKINIT)
+ {
+ grub_printf ("Secure launcher: AMD SKINIT\n");
+ }

return GRUB_ERR_NONE;
}
diff --git a/include/grub/i386/skinit.h b/include/grub/i386/skinit.h
new file mode 100644
index 000000000..bcad5e902
--- /dev/null
+++ b/include/grub/i386/skinit.h
@@ -0,0 +1,69 @@
+#ifndef __SKINIT_H__
+#define __SKINIT_H__
+
+#define GRUB_SKL_VERSION 0
+
+/* This is the setup_data type reserved for Secure Launch defined in bootparams */
+#define GRUB_SETUP_SECURE_LAUNCH 10
+
+/* The AMD defined structure layout for the SLB. The last two fields are SL specific */
+struct grub_sl_header
+{
+ grub_uint16_t skl_entry_point;
+ grub_uint16_t length;
+ grub_uint8_t reserved[62];
+ grub_uint16_t skl_info_offset;
+ grub_uint16_t bootloader_data_offset;
+} GRUB_PACKED;
+
+struct grub_skl_info
+{
+ grub_uint8_t uuid[16]; /* 78 f1 26 8e 04 92 11 e9 83 2a c8 5b 76 c4 cc 02 */
+ grub_uint32_t version;
+ grub_uint16_t msb_key_algo;
+ grub_uint8_t msb_key_hash[64]; /* Support up to SHA512 */
+} GRUB_PACKED;
+
+extern int grub_skl_set_module (const void *skl_base, grub_uint32_t size);
+extern grub_err_t grub_skl_setup_module (struct grub_slaunch_params *slparams);
+extern grub_err_t grub_skl_prepare_bootloader_data (struct grub_slaunch_params *slparams);
+extern void grub_skl_link_amd_info (struct grub_slaunch_params *slparams);
+
+extern grub_err_t grub_skinit_is_supported (void);
+extern grub_err_t grub_skinit_psp_memory_protect (struct grub_slaunch_params *slparams);
+extern grub_err_t grub_skinit_prepare_cpu (void);
+extern void grub_skinit_send_init_ipi_shorthand (void);
+
+#endif /* __SKINIT_H__ */
diff --git a/include/grub/slaunch.h b/include/grub/slaunch.h
index f63b8b379..ea22ece9d 100644
--- a/include/grub/slaunch.h
+++ b/include/grub/slaunch.h
@@ -24,6 +24,7 @@
/* Secure launch platform types. */
#define SLP_NONE 0
#define SLP_INTEL_TXT 1
+#define SLP_AMD_SKINIT 2

#define GRUB_SLAUNCH_TPM_EVT_LOG_SIZE (8 * GRUB_PAGE_SIZE)

@@ -52,6 +53,7 @@ struct grub_slaunch_params
grub_uint32_t platform_type;
struct linux_kernel_params *boot_params;
grub_uint64_t boot_params_base;
+ void *efi_memmap_mem;
struct grub_relocator *relocator;
grub_uint64_t slr_table_base;
grub_uint32_t slr_table_size;
@@ -120,10 +122,15 @@ grub_err_t grub_sl_txt_setup_linux (struct grub_slaunch_params *slparams,
struct grub_relocator *relocator,
grub_size_t total_size, grub_size_t prot_size,
void **prot_mode_mem, grub_addr_t *prot_mode_target);
+grub_err_t grub_sl_skinit_setup_linux (struct grub_slaunch_params *slparams,
+ struct grub_relocator *relocator,
+ grub_size_t total_size, grub_size_t prot_file_size,
+ void *prot_mode_mem, grub_addr_t prot_mode_target);

/* Linux EFI functions */
grub_err_t grub_sl_efi_txt_setup (struct grub_slaunch_params *slparams, void *kernel_addr,
grub_efi_loaded_image_t *loaded_image);
+
#endif /* ASM_FILE */

#endif /* GRUB_I386_SLAUNCH_H */
diff --git a/include/grub/slr_table.h b/include/grub/slr_table.h
index b9302472b..0bd15858e 100644
--- a/include/grub/slr_table.h
+++ b/include/grub/slr_table.h
@@ -194,6 +194,22 @@ struct grub_slr_entry_intel_info
struct grub_slr_txt_mtrr_state saved_bsp_mtrrs;
} GRUB_PACKED;

+/*
+ * AMD SKINIT Info table
+ */
+struct grub_slr_entry_amd_info
+{
+ struct grub_slr_entry_hdr hdr;
+ grub_uint64_t next;
+ grub_uint32_t type;
+ grub_uint32_t len;
+ grub_uint64_t slrt_size;
+ grub_uint64_t slrt_base;
+ grub_uint64_t boot_params_base;
+ grub_uint16_t psp_version;
+ grub_uint16_t reserved[3];
+} GRUB_PACKED;
+
/*
* UEFI config measurement entry
*/
--
2.47.1

Sergii Dmytruk

unread,
Dec 18, 2024, 2:08:25 PM12/18/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Ross Philipson <ross.ph...@oracle.com>

Changes built on the AMD Secure Launch base support for legacy Linux
this allows booting through the kernel's EFI stub and dlstub to start a
measured launch on AMD platforms.

Signed-off-by: Ross Philipson <ross.ph...@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
grub-core/loader/efi/dltrampoline.S | 35 ++++++++++--
grub-core/loader/efi/linux.c | 9 +++
grub-core/loader/slaunch/dlstub.c | 4 +-
grub-core/loader/slaunch/skinit.c | 26 +++++++--
grub-core/loader/slaunch/skl.c | 51 ++++++++++++++---
grub-core/loader/slaunch/x86_efi_linux.c | 72 ++++++++++++++++++++++++
include/grub/slaunch.h | 2 +
7 files changed, 176 insertions(+), 23 deletions(-)

diff --git a/grub-core/loader/efi/dltrampoline.S b/grub-core/loader/efi/dltrampoline.S
index 461e14271..e2d7a674f 100644
--- a/grub-core/loader/efi/dltrampoline.S
+++ b/grub-core/loader/efi/dltrampoline.S
@@ -18,16 +18,14 @@

#include <config.h>
#include <grub/symbol.h>
+#include <grub/slaunch.h>
+#include <grub/i386/crfr.h>
+#include <grub/i386/msr.h>

#define GRUB_SMX_LEAF_SENTER 4
#define CS_SEL32 0x0008
#define DS_SEL 0x0010

-#define CR0_PE 0x00000001
-#define CR0_MP 0x00000002
-#define CR0_TS 0x00000008
-#define CR0_NE 0x00000020
-
.file "dltrampoline.S"
.text

@@ -53,7 +51,7 @@ dl_trampoline:
lretq

.code32
-1: /* Now in IA-32e compatibility mode load data segments and do senter */
+1: /* Now in long compatibility (IA-32e), mode load data segments */
movw $DS_SEL, %ax
movw %ax, %ds
movw %ax, %es
@@ -61,12 +59,37 @@ dl_trampoline:
movw %ax, %fs
movw %ax, %gs

+ cmpl $SLP_AMD_SKINIT, %edx
+ je 1f
+
+ /* Intel SENTER */
movl $GRUB_SMX_LEAF_SENTER, %eax
movl %edi, %ebx
movl %esi, %ecx
xorl %edx, %edx
getsec

+1:
+ /* Turn paging off - we are identity mapped so we will survive */
+ movl %cr0, %eax
+ andl $~(GRUB_CR0_X86_PG | GRUB_CR0_X86_NE | GRUB_CR0_X86_TS | GRUB_CR0_X86_MP), %eax
+ movl %eax, %cr0
+
+ /* Disable long mode */
+ movl $(GRUB_MSR_X86_EFER), %ecx
+ rdmsr
+ andl $~(GRUB_MSR_EFER_LME), %eax
+ wrmsr
+
+ /* Now in protected mode, disable PAE */
+ movl %cr4, %eax
+ andl $~(GRUB_CR4_X86_PAE), %eax
+ movl %eax, %cr4
+
+ /* AMD SKINIT */
+ movl %edi, %eax
+ skinit
+
.align 8
dl_gdt:
/* Null Segment */
diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
index da13b4f62..f158b62f9 100644
--- a/grub-core/loader/efi/linux.c
+++ b/grub-core/loader/efi/linux.c
@@ -249,6 +249,15 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args)
goto unload;
}
}
+ else if (grub_slaunch_platform_type () == SLP_AMD_SKINIT)
+ {
+ err = grub_sl_efi_skinit_setup (&slparams, kernel_addr, loaded_image);
+ if (err != GRUB_ERR_NONE)
+ {
+ grub_error (err, "Secure Launch setup SKINIT failed");
+ goto unload;
+ }
+ }

grub_dprintf ("linux", "starting image %p\n", image_handle);
status = b->start_image (image_handle, 0, NULL);
diff --git a/grub-core/loader/slaunch/dlstub.c b/grub-core/loader/slaunch/dlstub.c
index fc1afed33..dbbd46f7d 100644
--- a/grub-core/loader/slaunch/dlstub.c
+++ b/grub-core/loader/slaunch/dlstub.c
@@ -35,7 +35,7 @@

GRUB_MOD_LICENSE ("GPLv3+");

-extern void dl_trampoline(grub_uint32_t dce_base, grub_uint32_t dce_size);
+extern void dl_trampoline(grub_uint32_t dce_base, grub_uint32_t dce_size, grub_uint32_t platform);

void dl_entry (grub_uint64_t dl_ctx)
{
@@ -124,7 +124,7 @@ void dl_entry (grub_uint64_t dl_ctx)
}
else if (slparams->boot_type == GRUB_SL_BOOT_TYPE_EFI)
{
- dl_trampoline (slparams->dce_base, slparams->dce_size);
+ dl_trampoline (slparams->dce_base, slparams->dce_size, slparams->platform_type);
}
else
{
diff --git a/grub-core/loader/slaunch/skinit.c b/grub-core/loader/slaunch/skinit.c
index 988b784b9..1dd6d3177 100644
--- a/grub-core/loader/slaunch/skinit.c
+++ b/grub-core/loader/slaunch/skinit.c
@@ -122,18 +122,32 @@ grub_skinit_psp_memory_protect (struct grub_slaunch_params *slparams)
grub_efi_memory_descriptor_t *memory_map_end;
grub_efi_memory_descriptor_t *desc;
struct grub_efi_info *efi_info;
- grub_uint64_t efi_memmap, tmr_end = 0;
+ grub_uint64_t efi_memmap, hi_val, tmr_end = 0;
grub_err_t err;

/* A bit of work to extract the v2.08 EFI info from the linux params */
efi_info = (struct grub_efi_info *)((grub_uint8_t *)&(boot_params->v0208)
+ 2*sizeof(grub_uint32_t));

- /*
- * On legacy Linux boots, the relocator is used to map the EFI memory map buffer
- * and return a virtual address to use. This virtual address is stashed in slparams.
- */
- efi_memmap = (grub_uint64_t)(grub_addr_t)slparams->efi_memmap_mem;
+ if (slparams->boot_type == GRUB_SL_BOOT_TYPE_EFI)
+ {
+ /*
+ * On EFI stub boots, the EFI memory map is fetched from the stub code so it
+ * needs to be gotten from the boot params on re-entry to the DL stub. The EFI
+ * info in boot params has physical addresses but everything is identity mapped.
+ */
+ efi_memmap = efi_info->efi_mmap;
+ hi_val = efi_info->efi_mmap_hi;
+ efi_memmap |= (hi_val << 32);
+ }
+ else
+ {
+ /*
+ * On legacy Linux boots, the relocator is used to map the EFI memory map buffer
+ * and return a virtual address to use. This virtual address is stashed in slparams.
+ */
+ efi_memmap = (grub_uint64_t)(grub_addr_t)slparams->efi_memmap_mem;
+ }

desc = (grub_efi_memory_descriptor_t *)(grub_addr_t) efi_memmap;
memory_map_end = (grub_efi_memory_descriptor_t *)(grub_addr_t) (efi_memmap + efi_info->efi_mmap_size);
diff --git a/grub-core/loader/slaunch/skl.c b/grub-core/loader/slaunch/skl.c
index 76ee5cf74..5de009754 100644
--- a/grub-core/loader/slaunch/skl.c
+++ b/grub-core/loader/slaunch/skl.c
@@ -40,6 +40,10 @@
#include <grub/i386/linux.h>
#include <grub/i386/psp.h>
#include <grub/i386/skinit.h>
+#include <grub/efi/efi.h>
+#include <grub/efi/memory.h>
+#undef GRUB_MEMORY_CPU_HEADER
+#include <grub/x86_64/efi/memory.h>

#define SLRT_SIZE GRUB_PAGE_SIZE

@@ -141,18 +145,47 @@ grub_skl_setup_module (struct grub_slaunch_params *slparams)
grub_phys_addr_t p_addr;
grub_uint8_t *v_addr;
grub_err_t err;
+#ifdef GRUB_MACHINE_EFI
+ grub_addr_t max_addr;
+#endif

- err = grub_relocator_alloc_chunk_align (slparams->relocator, &ch,
- 0, UP_TO_TOP32(SLB_SIZE), SLB_SIZE,
- SLB_MIN_ALIGNMENT,
- GRUB_RELOCATOR_PREFERENCE_HIGH,
- 1);
+ if (slparams->boot_type == GRUB_SL_BOOT_TYPE_LINUX)
+ {
+ err = grub_relocator_alloc_chunk_align (slparams->relocator, &ch,
+ 0, UP_TO_TOP32(SLB_SIZE), SLB_SIZE,
+ SLB_MIN_ALIGNMENT,
+ GRUB_RELOCATOR_PREFERENCE_HIGH,
+ 1);

- if (err != GRUB_ERR_NONE)
- return grub_error (err, N_("failed to allocate SLB"));
+ if (err != GRUB_ERR_NONE)
+ return grub_error (err, N_("failed to allocate SLB"));

- v_addr = get_virtual_current_address (ch);
- p_addr = get_physical_target_address (ch);
+ v_addr = get_virtual_current_address (ch);
+ p_addr = get_physical_target_address (ch);
+ }
+ else if (slparams->boot_type == GRUB_SL_BOOT_TYPE_EFI)
+ {
+#ifdef GRUB_MACHINE_EFI
+ max_addr = ALIGN_DOWN ((GRUB_EFI_MAX_USABLE_ADDRESS - SLB_SIZE),
+ GRUB_PAGE_SIZE);
+
+ v_addr = grub_efi_allocate_pages_real (max_addr,
+ GRUB_EFI_BYTES_TO_PAGES(SLB_SIZE + SLB_MIN_ALIGNMENT),
+ GRUB_EFI_ALLOCATE_MAX_ADDRESS,
+ GRUB_EFI_LOADER_DATA);
+ if (!v_addr)
+ return GRUB_ERR_OUT_OF_MEMORY;
+
+ v_addr = (grub_uint8_t *) ALIGN_UP ((grub_addr_t) v_addr, SLB_MIN_ALIGNMENT);
+ p_addr = (grub_addr_t) v_addr;
+#else
+ return GRUB_ERR_BUG;
+#endif
+ }
+ else
+ {
+ return grub_error (GRUB_ERR_BUG, N_("unknown dynamic launch boot type: %d"), slparams->boot_type);
+ }

grub_memcpy (v_addr, skl_module, skl_size);
skl_module = (struct grub_sl_header *) v_addr;
diff --git a/grub-core/loader/slaunch/x86_efi_linux.c b/grub-core/loader/slaunch/x86_efi_linux.c
index 1a237b42c..4ead208c7 100644
--- a/grub-core/loader/slaunch/x86_efi_linux.c
+++ b/grub-core/loader/slaunch/x86_efi_linux.c
@@ -33,6 +33,7 @@
#include <grub/i386/memory.h>
#include <grub/i386/linux.h>
#include <grub/i386/txt.h>
+#include <grub/i386/skinit.h>

GRUB_MOD_LICENSE ("GPLv3+");

@@ -210,3 +211,74 @@ fail:

return err;
}
+
+grub_err_t
+grub_sl_efi_skinit_setup (struct grub_slaunch_params *slparams, void *kernel_addr,
+ grub_efi_loaded_image_t *loaded_image)
+{
+ struct linux_kernel_params *lh = (struct linux_kernel_params *)kernel_addr;
+ grub_uint64_t image_base = (grub_uint64_t)loaded_image->image_base;
+ grub_efi_uint64_t image_size = loaded_image->image_size;
+ grub_uint8_t *logmem;
+ grub_addr_t max_addr;
+ grub_ssize_t start;
+ grub_err_t err;
+
+ slparams->boot_type = GRUB_SL_BOOT_TYPE_EFI;
+ slparams->platform_type = grub_slaunch_platform_type();
+
+ /* See comment in TXT setup function grub_efi_slaunch_setup_txt() */
+ slparams->boot_params = &boot_params;
+ slparams->boot_params_base = (grub_uint64_t)&boot_params;
+
+ start = (lh->setup_sects + 1) * 512;
+
+ /* See comment in TXT setup function grub_efi_slaunch_setup_txt() */
+ slparams->mle_mem = image_base + start;
+ slparams->mle_start = image_base + start;
+ slparams->mle_size = image_size - start;
+
+ max_addr = ALIGN_DOWN ((GRUB_EFI_MAX_USABLE_ADDRESS - GRUB_EFI_SLAUNCH_TPM_EVT_LOG_SIZE),
+ GRUB_PAGE_SIZE);
+
+ logmem = grub_efi_allocate_pages_real (max_addr,
+ GRUB_EFI_BYTES_TO_PAGES(GRUB_EFI_SLAUNCH_TPM_EVT_LOG_SIZE),
+ GRUB_EFI_ALLOCATE_MAX_ADDRESS,
+ GRUB_EFI_LOADER_DATA);
+ if (!logmem)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+ return GRUB_ERR_OUT_OF_MEMORY;
+ }
+
+ grub_memset (logmem, 0, GRUB_EFI_SLAUNCH_TPM_EVT_LOG_SIZE);
+ slparams->tpm_evt_log_base = (grub_uint64_t)logmem;
+ slparams->tpm_evt_log_size = GRUB_EFI_SLAUNCH_TPM_EVT_LOG_SIZE;
+
+ err = sl_efi_locate_mle_offset (slparams, kernel_addr, start);
+ if (err != GRUB_ERR_NONE)
+ goto fail;
+
+ /*
+ * AMD SKL final setup may relocate the SKL module. It is also what sets the SLRT and DCE
+ * values in slparams so this must be done before final setup and launch below.
+ */
+ err = grub_skl_setup_module (slparams);
+ if (err != GRUB_ERR_NONE)
+ goto fail;
+
+ err = grub_skl_prepare_bootloader_data (slparams);
+ if (err != GRUB_ERR_NONE)
+ goto fail;
+
+ err = sl_efi_install_slr_table (slparams);
+ if (err != GRUB_ERR_NONE)
+ goto fail;
+
+ return GRUB_ERR_NONE;
+
+fail:
+ grub_efi_free_pages ((grub_addr_t)logmem, GRUB_EFI_SLAUNCH_TPM_EVT_LOG_SIZE);
+
+ return err;
+}
diff --git a/include/grub/slaunch.h b/include/grub/slaunch.h
index ea22ece9d..e85700c69 100644
--- a/include/grub/slaunch.h
+++ b/include/grub/slaunch.h
@@ -130,6 +130,8 @@ grub_err_t grub_sl_skinit_setup_linux (struct grub_slaunch_params *slparams,
/* Linux EFI functions */
grub_err_t grub_sl_efi_txt_setup (struct grub_slaunch_params *slparams, void *kernel_addr,
grub_efi_loaded_image_t *loaded_image);
+grub_err_t grub_sl_efi_skinit_setup (struct grub_slaunch_params *slparams, void *kernel_addr,
+ grub_efi_loaded_image_t *loaded_image);

#endif /* ASM_FILE */

--
2.47.1

Sergii Dmytruk

unread,
Dec 18, 2024, 2:08:27 PM12/18/24
to grub-...@gnu.org, trenchbo...@googlegroups.com
From: Michał Żygowski <michal....@3mdeb.com>

Signed-off-by: Michał Żygowski <michal....@3mdeb.com>
Signed-off-by: Tomasz Żyjewski <tomasz....@3mdeb.com>
Signed-off-by: Krystian Hebel <krystia...@3mdeb.com>
Signed-off-by: Sergii Dmytruk <sergii....@3mdeb.com>
---
grub-core/loader/multiboot_mbi2.c | 14 +++++++++++++-
grub-core/loader/slaunch/skl.c | 2 +-
2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c
index dcbfbed1f..9b480c0c2 100644
--- a/grub-core/loader/multiboot_mbi2.c
+++ b/grub-core/loader/multiboot_mbi2.c
@@ -37,6 +37,7 @@
#include <grub/net.h>
#include <grub/lib/cmdline.h>
#include <grub/i386/memory.h>
+#include <grub/i386/skinit.h>
#include <grub/i386/txt.h>
#include <grub/slaunch.h>
#include <grub/slr_table.h>
@@ -430,7 +431,8 @@ grub_multiboot2_load (grub_file_t file, const char *filename)
slparams->tpm_evt_log_base = get_physical_target_address (ch);
slparams->tpm_evt_log_size = GRUB_SLAUNCH_TPM_EVT_LOG_SIZE;

- if (slparams->platform_type == SLP_INTEL_TXT)
+ /* It's OK to call this for AMD SKINIT because SKL erases the log before use. */
+ if (slparams->platform_type == SLP_INTEL_TXT || slparams->platform_type == SLP_AMD_SKINIT)
grub_txt_init_tpm_event_log (get_virtual_current_address (ch),
slparams->tpm_evt_log_size);

@@ -1246,6 +1248,16 @@ grub_multiboot2_perform_slaunch (grub_uint32_t mbi_target,
if (err != GRUB_ERR_NONE)
return grub_error (err, "TXT boot preparation failed");
}
+ else if (slparams->platform_type == SLP_AMD_SKINIT)
+ {
+ err = grub_skl_setup_module (slparams);
+ if (err != GRUB_ERR_NONE)
+ return grub_error (err, "Failed to setup SKL for Multiboot2");
+
+ err = grub_skl_prepare_bootloader_data (slparams);
+ if (err != GRUB_ERR_NONE)
+ return grub_error (err, "SKL preparations have failed");
+ }
else
return grub_error (GRUB_ERR_BAD_DEVICE,
N_("Unknown secure launcher platform type: %d\n"), slparams->platform_type);
diff --git a/grub-core/loader/slaunch/skl.c b/grub-core/loader/slaunch/skl.c
index 5de009754..465f2fb7e 100644
--- a/grub-core/loader/slaunch/skl.c
+++ b/grub-core/loader/slaunch/skl.c
@@ -149,7 +149,7 @@ grub_skl_setup_module (struct grub_slaunch_params *slparams)
grub_addr_t max_addr;
#endif

- if (slparams->boot_type == GRUB_SL_BOOT_TYPE_LINUX)
+ if (slparams->boot_type == GRUB_SL_BOOT_TYPE_LINUX || slparams->boot_type == GRUB_SL_BOOT_TYPE_MB2)
{
err = grub_relocator_alloc_chunk_align (slparams->relocator, &ch,
0, UP_TO_TOP32(SLB_SIZE), SLB_SIZE,
--
2.47.1

Reply all
Reply to author
Forward
0 new messages