From: Ross Philipson <ross.philip...@oracle.com> Add core implementation for AMD SKINIT Secure Launch in GRUB based on Linux legacy boot protocol.
Signed-off-by: Ross Philipson <ross.philip...@oracle.com> Signed-off-by: Sergii Dmytruk <sergii.dmyt...@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 @@ +/* + * 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/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 @@ +/* + * 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/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 @@ +/* + * 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 __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 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel