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