From: Ross Philipson <ross.philip...@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.philip...@oracle.com>
Signed-off-by: Sergii Dmytruk <sergii.dmyt...@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


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to