[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC PATCH 6/7] efi/slaunch: Add AMD Secure Launch support for Linux EFI
From: |
Sergii Dmytruk |
Subject: |
[RFC PATCH 6/7] efi/slaunch: Add AMD Secure Launch support for Linux EFI stub boot |
Date: |
Wed, 18 Dec 2024 21:08:02 +0200 |
From: Ross Philipson <ross.philipson@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.philipson@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii.dmytruk@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
- [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 <=
- [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, 2024/12/18