From 3128d7248f2ad389b8e9a3e252958cbfbd1898ee Mon Sep 17 00:00:00 2001 From: "Daniel P. Smith" Date: Fri, 15 Nov 2024 08:12:00 -0500 Subject: [PATCH 01/46] x86/boot: introduce module release A precarious approach was used to release the pages used to hold a boot module. The precariousness stemmed from the fact that in the case of PV dom0, the initrd module pages may be either mapped or copied into the dom0 address space. In the former case, the PV dom0 construction code will set the size of the module to zero, relying on discard_initial_images() to skip any modules with a size of zero. In the latter case, the pages are freed by the PV dom0 construction code. This freeing of pages is done so that in either case, the initrd variable can be reused for tracking the initrd location in dom0 memory through the remaining dom0 construction code. To encapsulate the logical action of releasing a boot module, the function release_boot_module() is introduced along with the `released` flag added to boot module. The boot module flag `released` allows the tracking of when a boot module has been released by release_boot_module(). As part of adopting release_boot_module() the function discard_initial_images() is renamed to free_boot_modules(), a name that better reflects the functions actions. Signed-off-by: Daniel P. Smith Reviewed-by: Andrew Cooper --- xen/arch/x86/hvm/dom0_build.c | 2 +- xen/arch/x86/include/asm/bootinfo.h | 2 ++ xen/arch/x86/include/asm/setup.h | 4 +++- xen/arch/x86/pv/dom0_build.c | 27 +++++++++++++-------------- xen/arch/x86/setup.c | 27 +++++++++++++++------------ 5 files changed, 34 insertions(+), 28 deletions(-) diff --git a/xen/arch/x86/hvm/dom0_build.c b/xen/arch/x86/hvm/dom0_build.c index 35d8d6a070..b4433bed30 100644 --- a/xen/arch/x86/hvm/dom0_build.c +++ b/xen/arch/x86/hvm/dom0_build.c @@ -755,7 +755,7 @@ static int __init pvh_load_kernel( } /* Free temporary buffers. */ - discard_initial_images(); + free_boot_modules(); if ( cmdline != NULL ) { diff --git a/xen/arch/x86/include/asm/bootinfo.h b/xen/arch/x86/include/asm/bootinfo.h index b9c94b370d..f768763867 100644 --- a/xen/arch/x86/include/asm/bootinfo.h +++ b/xen/arch/x86/include/asm/bootinfo.h @@ -34,8 +34,10 @@ struct boot_module { /* * Module State Flags: * relocated: indicates module has been relocated in memory. + * released: indicates module's pages have been freed. */ bool relocated:1; + bool released:1; /* * A boot module may need decompressing by Xen. Headroom is an estimate of diff --git a/xen/arch/x86/include/asm/setup.h b/xen/arch/x86/include/asm/setup.h index 8a415087e9..4ad4936378 100644 --- a/xen/arch/x86/include/asm/setup.h +++ b/xen/arch/x86/include/asm/setup.h @@ -34,13 +34,15 @@ void setup_io_bitmap(struct domain *d); extern struct boot_info xen_boot_info; unsigned long initial_images_nrpages(nodeid_t node); -void discard_initial_images(void); +void free_boot_modules(void); struct boot_module; void *bootstrap_map_bm(const struct boot_module *bm); void *bootstrap_map(const module_t *mod); void bootstrap_unmap(void); +void release_boot_module(struct boot_module *bm); + struct rangeset; int remove_xen_ranges(struct rangeset *r); diff --git a/xen/arch/x86/pv/dom0_build.c b/xen/arch/x86/pv/dom0_build.c index 9cf4519111..f52ede1786 100644 --- a/xen/arch/x86/pv/dom0_build.c +++ b/xen/arch/x86/pv/dom0_build.c @@ -649,9 +649,12 @@ static int __init dom0_construct(struct boot_info *bi, struct domain *d) } memcpy(page_to_virt(page), mfn_to_virt(initrd->mod->mod_start), initrd_len); - mpt_alloc = pfn_to_paddr(initrd->mod->mod_start); - init_domheap_pages(mpt_alloc, - mpt_alloc + PAGE_ALIGN(initrd_len)); + /* + * The initrd was copied but the initrd variable is reused in the + * calculations below. As to not leak the memory used for the + * module free at this time. + */ + release_boot_module(initrd); initrd_mfn = mfn_x(page_to_mfn(page)); initrd->mod->mod_start = initrd_mfn; } @@ -660,18 +663,14 @@ static int __init dom0_construct(struct boot_info *bi, struct domain *d) while ( count-- ) if ( assign_pages(mfn_to_page(_mfn(mfn++)), 1, d, 0) ) BUG(); + /* + * We have mapped the initrd directly into dom0, and assigned the + * pages. Tell the boot_module handling that we've freed it, so the + * memory is left alone. + */ + initrd->released = true; } - /* - * We have either: - * - Mapped the initrd directly into dom0, or - * - Copied it and freed the module. - * - * Either way, tell discard_initial_images() to not free it a second - * time. - */ - initrd->mod->mod_end = 0; - iommu_memory_setup(d, "initrd", mfn_to_page(_mfn(initrd_mfn)), PFN_UP(initrd_len), &flush_flags); } @@ -875,7 +874,7 @@ static int __init dom0_construct(struct boot_info *bi, struct domain *d) } /* Free temporary buffers. */ - discard_initial_images(); + free_boot_modules(); /* Set up start info area. */ si = (start_info_t *)vstartinfo_start; diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 302ff61e2b..a3b4d59e80 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -346,27 +346,30 @@ unsigned long __init initial_images_nrpages(nodeid_t node) return nr; } -void __init discard_initial_images(void) /* a.k.a. Free boot modules */ +void __init release_boot_module(struct boot_module *bm) +{ + uint64_t start = pfn_to_paddr(bm->mod->mod_start); + uint64_t size = bm->mod->mod_end; + + ASSERT(!bm->released); + + init_domheap_pages(start, start + PAGE_ALIGN(size)); + + bm->released = true; +} + +void __init free_boot_modules(void) { struct boot_info *bi = &xen_boot_info; unsigned int i; for ( i = 0; i < bi->nr_modules; ++i ) { - uint64_t start = pfn_to_paddr(bi->mods[i].mod->mod_start); - uint64_t size = bi->mods[i].mod->mod_end; - - /* - * Sometimes the initrd is mapped, rather than copied, into dom0. - * Size being 0 is how we're instructed to leave the module alone. - */ - if ( size == 0 ) + if ( bi->mods[i].released ) continue; - init_domheap_pages(start, start + PAGE_ALIGN(size)); + release_boot_module(&bi->mods[i]); } - - bi->nr_modules = 0; } static void __init init_idle_domain(void) From 3ac41c60e8d29bde63e0f6a0ad2892b60b838ab7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= Date: Tue, 19 Nov 2024 11:34:41 +0100 Subject: [PATCH 02/46] x86/mm: fix IS_LnE_ALIGNED() to comply with Misra Rule 20.7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While not strictly needed to guarantee operator precedence is as expected, add the parentheses to comply with Misra Rule 20.7. No functional change intended. Reported-by: Andrew Cooper Fixes: 5b52e1b0436f ('x86/mm: skip super-page alignment checks for non-present entries') Signed-off-by: Roger Pau Monné Acked-by: Jan Beulich Acked-by: Andrew Cooper --- xen/arch/x86/mm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 494c14e80f..fa21903eb2 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -5498,7 +5498,7 @@ int map_pages_to_xen( * be INVALID_MFN, since alignment is only relevant for present entries. */ #define IS_LnE_ALIGNED(v, m, n) ({ \ - mfn_t m_ = m; \ + mfn_t m_ = (m); \ \ ASSERT(!mfn_eq(m_, INVALID_MFN)); \ IS_ALIGNED(PFN_DOWN(v) | mfn_x(m_), \ From 9e8c97f3eb4662533a1dd2e2ce17d4025bd2726b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= Date: Tue, 19 Nov 2024 13:34:53 +0000 Subject: [PATCH 03/46] x86/msi: prune unused macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No functional change. Signed-off-by: Roger Pau Monné Acked-by: Andrew Cooper --- xen/arch/x86/include/asm/msi.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/xen/arch/x86/include/asm/msi.h b/xen/arch/x86/include/asm/msi.h index 748bc3cd6d..62a40e7298 100644 --- a/xen/arch/x86/include/asm/msi.h +++ b/xen/arch/x86/include/asm/msi.h @@ -156,24 +156,17 @@ int msi_free_irq(struct msi_desc *entry); ( (is64bit == 1) ? base+PCI_MSI_MASK_BIT : base+PCI_MSI_MASK_BIT-4) #define msi_pending_bits_reg(base, is64bit) \ ((base) + PCI_MSI_MASK_BIT + ((is64bit) ? 4 : 0)) -#define msi_disable(control) control &= ~PCI_MSI_FLAGS_ENABLE #define multi_msi_capable(control) \ (1 << ((control & PCI_MSI_FLAGS_QMASK) >> 1)) #define multi_msi_enable(control, num) \ control |= (((fls(num) - 1) << 4) & PCI_MSI_FLAGS_QSIZE); #define is_64bit_address(control) (!!(control & PCI_MSI_FLAGS_64BIT)) #define is_mask_bit_support(control) (!!(control & PCI_MSI_FLAGS_MASKBIT)) -#define msi_enable(control, num) multi_msi_enable(control, num); \ - control |= PCI_MSI_FLAGS_ENABLE #define msix_control_reg(base) (base + PCI_MSIX_FLAGS) #define msix_table_offset_reg(base) (base + PCI_MSIX_TABLE) #define msix_pba_offset_reg(base) (base + PCI_MSIX_PBA) -#define msix_enable(control) control |= PCI_MSIX_FLAGS_ENABLE -#define msix_disable(control) control &= ~PCI_MSIX_FLAGS_ENABLE #define msix_table_size(control) ((control & PCI_MSIX_FLAGS_QSIZE)+1) -#define msix_unmask(address) (address & ~PCI_MSIX_VECTOR_BITMASK) -#define msix_mask(address) (address | PCI_MSIX_VECTOR_BITMASK) /* * MSI Defined Data Structures From 488579e956e086c21bc6750b1b77eb0efd22cfa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= Date: Tue, 19 Nov 2024 11:34:42 +0100 Subject: [PATCH 04/46] x86/msi: fix Misra Rule 20.7 in msi.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adjust the macros to parenthesize their arguments. Use MASK_EXTR()/MASK_INSR() where appropriate. No functional change intended. Signed-off-by: Roger Pau Monné Reviewed-by: Andrew Cooper --- xen/arch/x86/include/asm/msi.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/xen/arch/x86/include/asm/msi.h b/xen/arch/x86/include/asm/msi.h index 62a40e7298..63adb19820 100644 --- a/xen/arch/x86/include/asm/msi.h +++ b/xen/arch/x86/include/asm/msi.h @@ -147,26 +147,26 @@ int msi_free_irq(struct msi_desc *entry); */ #define NR_HP_RESERVED_VECTORS 20 -#define msi_control_reg(base) (base + PCI_MSI_FLAGS) -#define msi_lower_address_reg(base) (base + PCI_MSI_ADDRESS_LO) -#define msi_upper_address_reg(base) (base + PCI_MSI_ADDRESS_HI) +#define msi_control_reg(base) ((base) + PCI_MSI_FLAGS) +#define msi_lower_address_reg(base) ((base) + PCI_MSI_ADDRESS_LO) +#define msi_upper_address_reg(base) ((base) + PCI_MSI_ADDRESS_HI) #define msi_data_reg(base, is64bit) \ - ( (is64bit == 1) ? base+PCI_MSI_DATA_64 : base+PCI_MSI_DATA_32 ) + ((base) + ((is64bit) ? PCI_MSI_DATA_64 : PCI_MSI_DATA_32)) #define msi_mask_bits_reg(base, is64bit) \ - ( (is64bit == 1) ? base+PCI_MSI_MASK_BIT : base+PCI_MSI_MASK_BIT-4) + ((base) + PCI_MSI_MASK_BIT - ((is64bit) ? 0 : 4)) #define msi_pending_bits_reg(base, is64bit) \ ((base) + PCI_MSI_MASK_BIT + ((is64bit) ? 4 : 0)) #define multi_msi_capable(control) \ - (1 << ((control & PCI_MSI_FLAGS_QMASK) >> 1)) + (1U << MASK_EXTR(control, PCI_MSI_FLAGS_QMASK)) #define multi_msi_enable(control, num) \ - control |= (((fls(num) - 1) << 4) & PCI_MSI_FLAGS_QSIZE); -#define is_64bit_address(control) (!!(control & PCI_MSI_FLAGS_64BIT)) -#define is_mask_bit_support(control) (!!(control & PCI_MSI_FLAGS_MASKBIT)) - -#define msix_control_reg(base) (base + PCI_MSIX_FLAGS) -#define msix_table_offset_reg(base) (base + PCI_MSIX_TABLE) -#define msix_pba_offset_reg(base) (base + PCI_MSIX_PBA) -#define msix_table_size(control) ((control & PCI_MSIX_FLAGS_QSIZE)+1) + ((control) |= MASK_INSR(fls(num) - 1, PCI_MSI_FLAGS_QSIZE)) +#define is_64bit_address(control) (!!((control) & PCI_MSI_FLAGS_64BIT)) +#define is_mask_bit_support(control) (!!((control) & PCI_MSI_FLAGS_MASKBIT)) + +#define msix_control_reg(base) ((base) + PCI_MSIX_FLAGS) +#define msix_table_offset_reg(base) ((base) + PCI_MSIX_TABLE) +#define msix_pba_offset_reg(base) ((base) + PCI_MSIX_PBA) +#define msix_table_size(control) (((control) & PCI_MSIX_FLAGS_QSIZE) + 1) /* * MSI Defined Data Structures From 429840a81ec7a6e2d6b4c4c1f249b772ee9fec13 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Mon, 18 Nov 2024 10:51:18 +0000 Subject: [PATCH 05/46] xen/bootinfo: Include declaration for fw_unreserved_regions() Eclair complains that fw_unreserved_regions() can't see it's declaration. Include to address this. This makes Misra Rule 8.4 clean on ARM, so tag it as such. Signed-off-by: Andrew Cooper Reviewed-by: Stefano Stabellini --- automation/eclair_analysis/ECLAIR/tagging.ecl | 2 +- xen/common/device-tree/bootinfo.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/automation/eclair_analysis/ECLAIR/tagging.ecl b/automation/eclair_analysis/ECLAIR/tagging.ecl index 9318e5b10c..7944ce2ee3 100644 --- a/automation/eclair_analysis/ECLAIR/tagging.ecl +++ b/automation/eclair_analysis/ECLAIR/tagging.ecl @@ -115,7 +115,7 @@ if(string_equal(target,"x86_64"), ) if(string_equal(target,"arm64"), - service_selector({"additional_clean_guidelines","MC3R1.R2.1||MC3R1.R5.3||MC3.R11.2||MC3R1.R16.6||MC3R1.R20.7"}) + service_selector({"additional_clean_guidelines","MC3R1.R2.1||MC3R1.R5.3||MC3R1.R8.4||MC3.R11.2||MC3R1.R16.6||MC3R1.R20.7"}) ) -reports+={clean:added,"service(clean_guidelines_common||additional_clean_guidelines)"} diff --git a/xen/common/device-tree/bootinfo.c b/xen/common/device-tree/bootinfo.c index f2e6a1145b..3738eb57ff 100644 --- a/xen/common/device-tree/bootinfo.c +++ b/xen/common/device-tree/bootinfo.c @@ -17,6 +17,8 @@ #include #include +#include + struct bootinfo __initdata bootinfo = BOOTINFO_INIT; const char * __init boot_module_kind_as_string(bootmodule_kind kind) From a1ed107f59efbc9fef1de5f81d006e951a07e5f9 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Mon, 18 Nov 2024 16:57:29 +0000 Subject: [PATCH 06/46] x86/boot: Introduce boot-helpers.h Eclair complains that neither reloc_trampoline{32,64}() can see their declarations. reloc_trampoline32() needs to become asmlinkage, while reloc_trampoline64() needs declaring properly in a way that both efi-boot.h and reloc-trampoline.c can see. Introduce boot-helpers.h for the purpose. Signed-off-by: Andrew Cooper Reviewed-by: Jan Beulich --- xen/arch/x86/boot/reloc-trampoline.c | 4 +++- xen/arch/x86/efi/efi-boot.h | 4 ++-- xen/arch/x86/include/asm/boot-helpers.h | 13 +++++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 xen/arch/x86/include/asm/boot-helpers.h diff --git a/xen/arch/x86/boot/reloc-trampoline.c b/xen/arch/x86/boot/reloc-trampoline.c index d5548eb08f..e35e7c78aa 100644 --- a/xen/arch/x86/boot/reloc-trampoline.c +++ b/xen/arch/x86/boot/reloc-trampoline.c @@ -2,13 +2,15 @@ #include #include + +#include #include extern const int32_t __trampoline_rel_start[], __trampoline_rel_stop[]; extern const int32_t __trampoline_seg_start[], __trampoline_seg_stop[]; #if defined(__i386__) -void reloc_trampoline32(void) +void asmlinkage reloc_trampoline32(void) #elif defined (__x86_64__) void reloc_trampoline64(void) #else diff --git a/xen/arch/x86/efi/efi-boot.h b/xen/arch/x86/efi/efi-boot.h index 9d3f2b7144..1d8902a9a7 100644 --- a/xen/arch/x86/efi/efi-boot.h +++ b/xen/arch/x86/efi/efi-boot.h @@ -4,6 +4,8 @@ * therefore can define arch specific global variables. */ #include + +#include #include #include #include @@ -103,8 +105,6 @@ static void __init efi_arch_relocate_image(unsigned long delta) } } -void reloc_trampoline64(void); - static void __init relocate_trampoline(unsigned long phys) { trampoline_phys = phys; diff --git a/xen/arch/x86/include/asm/boot-helpers.h b/xen/arch/x86/include/asm/boot-helpers.h new file mode 100644 index 0000000000..391e16a730 --- /dev/null +++ b/xen/arch/x86/include/asm/boot-helpers.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Declarations for helper functions compiled for both 32bit and 64bit. + * + * The 32bit forms are only used from assembly, so no declarations are + * provided. + */ +#ifndef X86_BOOT_HELPERS_H +#define X86_BOOT_HELPERS_H + +void reloc_trampoline64(void); + +#endif /* X86_BOOT_HELPERS_H */ From 6308301208d60fcd2b9125fe6a602cefa80392e6 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Tue, 19 Nov 2024 09:12:43 +0100 Subject: [PATCH 07/46] x86/pmstat: deal with Misra 8.4 violations While the override #define-s in x86_64/platform_hypercall.c are good for the consuming side of the compat variants of set_{cx,px}_pminfo(), the producers lack the respective declarations. Include pmstat.h early, before the overrides are put in place, while adding explicit declarations of the compat functions (alongside structure forward declarations). Reported-by: Andrew Cooper Signed-off-by: Jan Beulich Acked-by: Andrew Cooper Tested-by: Andrew Cooper --- xen/arch/x86/x86_64/platform_hypercall.c | 2 +- xen/include/xen/pmstat.h | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/xen/arch/x86/x86_64/platform_hypercall.c b/xen/arch/x86/x86_64/platform_hypercall.c index 347f5d6533..9ab631c17f 100644 --- a/xen/arch/x86/x86_64/platform_hypercall.c +++ b/xen/arch/x86/x86_64/platform_hypercall.c @@ -4,8 +4,8 @@ EMIT_FILE; -#include #include +#include #define xen_platform_op compat_platform_op #define xen_platform_op_t compat_platform_op_t diff --git a/xen/include/xen/pmstat.h b/xen/include/xen/pmstat.h index e6ab1423a9..8350403e95 100644 --- a/xen/include/xen/pmstat.h +++ b/xen/include/xen/pmstat.h @@ -7,6 +7,14 @@ int set_px_pminfo(uint32_t acpi_id, struct xen_processor_performance *perf); long set_cx_pminfo(uint32_t acpi_id, struct xen_processor_power *power); + +#ifdef CONFIG_COMPAT +struct compat_processor_performance; +int compat_set_px_pminfo(uint32_t acpi_id, struct compat_processor_performance *perf); +struct compat_processor_power; +long compat_set_cx_pminfo(uint32_t acpi_id, struct compat_processor_power *power); +#endif + uint32_t pmstat_get_cx_nr(unsigned int cpu); int pmstat_get_cx_stat(unsigned int cpu, struct pm_cx_stat *stat); int pmstat_reset_cx_stat(unsigned int cpu); From cd7cc5320bb28a57f8243803e6130b4cecb961bb Mon Sep 17 00:00:00 2001 From: "Daniel P. Smith" Date: Fri, 15 Nov 2024 08:12:01 -0500 Subject: [PATCH 08/46] x86/boot: add start and size fields to struct boot_module Introduce the start and size fields to struct boot_module and assigns their value during boot_info construction. All uses of module_t to get the address and size of a module are replaced with start and size. The EFI entry point is a special case, as the EFI file loading boot service may load a file beyond the 4G barrier. As a result, to make the address fit in the 32bit integer used by the MB1 module_t structure, the frame number is stored in mod_start and size in mod_end. Until the EFI entry point is enlightened to work with boot_info and boot_module, multiboot_fill_boot_info will handle the alternate values in mod_start and mod_end when EFI is detected. A result of the switch to start/size removes all uses of the mod field in struct boot_modules, along with the uses of bootstrap_map() and release_module() functions. With all usage gone, they all are dropped here. Signed-off-by: Daniel P. Smith Reviewed-by: Jason Andryuk Reviewed-by: Andrew Cooper --- xen/arch/x86/cpu/microcode/core.c | 8 +-- xen/arch/x86/hvm/dom0_build.c | 6 +- xen/arch/x86/include/asm/bootinfo.h | 6 +- xen/arch/x86/include/asm/setup.h | 1 - xen/arch/x86/pv/dom0_build.c | 15 +++-- xen/arch/x86/setup.c | 89 ++++++++++++++--------------- xen/xsm/xsm_policy.c | 2 +- 7 files changed, 60 insertions(+), 67 deletions(-) diff --git a/xen/arch/x86/cpu/microcode/core.c b/xen/arch/x86/cpu/microcode/core.c index 22bc0875eb..4811b5ffb1 100644 --- a/xen/arch/x86/cpu/microcode/core.c +++ b/xen/arch/x86/cpu/microcode/core.c @@ -688,8 +688,8 @@ static int __init cf_check microcode_init_cache(void) /* early_microcode_load() didn't leave us any work to do. */ return 0; - size = bi->mods[early_mod_idx].mod->mod_end; - data = __mfn_to_virt(bi->mods[early_mod_idx].mod->mod_start); + size = bi->mods[early_mod_idx].size; + data = __va(bi->mods[early_mod_idx].start); /* * If opt_scan is set, we're looking for a CPIO archive rather than a raw @@ -765,7 +765,7 @@ static int __init early_microcode_load(struct boot_info *bi) bm->type != BOOTMOD_RAMDISK ) continue; - size = bm->mod->mod_end; + size = bm->size; data = bootstrap_map_bm(bm); if ( !data ) { @@ -819,7 +819,7 @@ static int __init early_microcode_load(struct boot_info *bi) } bi->mods[idx].type = BOOTMOD_MICROCODE; - size = bi->mods[idx].mod->mod_end; + size = bi->mods[idx].size; data = bootstrap_map_bm(&bi->mods[idx]); if ( !data ) { diff --git a/xen/arch/x86/hvm/dom0_build.c b/xen/arch/x86/hvm/dom0_build.c index b4433bed30..ce5b5c31b3 100644 --- a/xen/arch/x86/hvm/dom0_build.c +++ b/xen/arch/x86/hvm/dom0_build.c @@ -649,8 +649,8 @@ static int __init pvh_load_kernel( { void *image_base = bootstrap_map_bm(image); void *image_start = image_base + image->headroom; - unsigned long image_len = image->mod->mod_end; - unsigned long initrd_len = initrd ? initrd->mod->mod_end : 0; + unsigned long image_len = image->size; + unsigned long initrd_len = initrd ? initrd->size : 0; const char *cmdline = image->cmdline_pa ? __va(image->cmdline_pa) : NULL; struct elf_binary elf; struct elf_dom_parms parms; @@ -726,7 +726,7 @@ static int __init pvh_load_kernel( if ( initrd != NULL ) { - rc = hvm_copy_to_guest_phys(last_addr, mfn_to_virt(initrd->mod->mod_start), + rc = hvm_copy_to_guest_phys(last_addr, __va(initrd->start), initrd_len, v); if ( rc ) { diff --git a/xen/arch/x86/include/asm/bootinfo.h b/xen/arch/x86/include/asm/bootinfo.h index f768763867..f8b4229130 100644 --- a/xen/arch/x86/include/asm/bootinfo.h +++ b/xen/arch/x86/include/asm/bootinfo.h @@ -26,9 +26,6 @@ enum bootmod_type { }; struct boot_module { - /* Transitionary only */ - module_t *mod; - enum bootmod_type type; /* @@ -62,6 +59,9 @@ struct boot_module { unsigned long headroom; paddr_t cmdline_pa; + + paddr_t start; + size_t size; }; /* diff --git a/xen/arch/x86/include/asm/setup.h b/xen/arch/x86/include/asm/setup.h index 4ad4936378..5c2391a868 100644 --- a/xen/arch/x86/include/asm/setup.h +++ b/xen/arch/x86/include/asm/setup.h @@ -38,7 +38,6 @@ void free_boot_modules(void); struct boot_module; void *bootstrap_map_bm(const struct boot_module *bm); -void *bootstrap_map(const module_t *mod); void bootstrap_unmap(void); void release_boot_module(struct boot_module *bm); diff --git a/xen/arch/x86/pv/dom0_build.c b/xen/arch/x86/pv/dom0_build.c index f52ede1786..f54d1da5c6 100644 --- a/xen/arch/x86/pv/dom0_build.c +++ b/xen/arch/x86/pv/dom0_build.c @@ -422,14 +422,14 @@ static int __init dom0_construct(struct boot_info *bi, struct domain *d) image = &bi->mods[i]; image_base = bootstrap_map_bm(image); - image_len = image->mod->mod_end; + image_len = image->size; image_start = image_base + image->headroom; i = first_boot_module_index(bi, BOOTMOD_RAMDISK); if ( i < bi->nr_modules ) { initrd = &bi->mods[i]; - initrd_len = initrd->mod->mod_end; + initrd_len = initrd->size; } d->max_pages = ~0U; @@ -631,7 +631,7 @@ static int __init dom0_construct(struct boot_info *bi, struct domain *d) initrd_pfn = vinitrd_start ? (vinitrd_start - v_start) >> PAGE_SHIFT : domain_tot_pages(d); - initrd_mfn = initrd->mod->mod_start; + initrd_mfn = paddr_to_pfn(initrd->start); mfn = initrd_mfn; count = PFN_UP(initrd_len); if ( d->arch.physaddr_bitsize && @@ -647,8 +647,7 @@ static int __init dom0_construct(struct boot_info *bi, struct domain *d) free_domheap_pages(page, order); page += 1UL << order; } - memcpy(page_to_virt(page), mfn_to_virt(initrd->mod->mod_start), - initrd_len); + memcpy(page_to_virt(page), __va(initrd->start), initrd_len); /* * The initrd was copied but the initrd variable is reused in the * calculations below. As to not leak the memory used for the @@ -656,7 +655,7 @@ static int __init dom0_construct(struct boot_info *bi, struct domain *d) */ release_boot_module(initrd); initrd_mfn = mfn_x(page_to_mfn(page)); - initrd->mod->mod_start = initrd_mfn; + initrd->start = pfn_to_paddr(initrd_mfn); } else { @@ -683,7 +682,7 @@ static int __init dom0_construct(struct boot_info *bi, struct domain *d) nr_pages - domain_tot_pages(d)); if ( initrd ) { - mpt_alloc = pfn_to_paddr(initrd->mod->mod_start); + mpt_alloc = initrd->start; printk("\n Init. ramdisk: %"PRIpaddr"->%"PRIpaddr, mpt_alloc, mpt_alloc + initrd_len); } @@ -911,7 +910,7 @@ static int __init dom0_construct(struct boot_info *bi, struct domain *d) if ( pfn >= initrd_pfn ) { if ( pfn < initrd_pfn + PFN_UP(initrd_len) ) - mfn = initrd->mod->mod_start + (pfn - initrd_pfn); + mfn = paddr_to_pfn(initrd->start) + (pfn - initrd_pfn); else mfn -= PFN_UP(initrd_len); } diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index a3b4d59e80..1239e91b83 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -314,13 +314,29 @@ static struct boot_info *__init multiboot_fill_boot_info( */ for ( i = 0; i < MAX_NR_BOOTMODS && i < bi->nr_modules; i++ ) { - bi->mods[i].mod = &mods[i]; - bi->mods[i].cmdline_pa = mods[i].string; + + if ( efi_enabled(EFI_LOADER) ) + { + /* + * The EFI loader gives us modules which are in frame/size. Switch + * to address/size. + */ + bi->mods[i].start = pfn_to_paddr(mods[i].mod_start); + bi->mods[i].size = mods[i].mod_end; + } + else + { + /* + * PVH and BIOS loaders give us modules which are start/end. + * Switch to address/size. + */ + bi->mods[i].start = mods[i].mod_start; + bi->mods[i].size = mods[i].mod_end - mods[i].mod_start; + } } /* Variable 'i' should be one entry past the last module. */ - bi->mods[i].mod = &mods[bi->nr_modules]; bi->mods[i].type = BOOTMOD_XEN; return bi; @@ -336,8 +352,8 @@ unsigned long __init initial_images_nrpages(nodeid_t node) for ( nr = i = 0; i < bi->nr_modules; ++i ) { - unsigned long start = bi->mods[i].mod->mod_start; - unsigned long end = start + PFN_UP(bi->mods[i].mod->mod_end); + unsigned long start = paddr_to_pfn(bi->mods[i].start); + unsigned long end = start + PFN_UP(bi->mods[i].size); if ( end > node_start && node_end > start ) nr += min(node_end, end) - max(node_start, start); @@ -348,12 +364,9 @@ unsigned long __init initial_images_nrpages(nodeid_t node) void __init release_boot_module(struct boot_module *bm) { - uint64_t start = pfn_to_paddr(bm->mod->mod_start); - uint64_t size = bm->mod->mod_end; - ASSERT(!bm->released); - init_domheap_pages(start, start + PAGE_ALIGN(size)); + init_domheap_pages(bm->start, bm->start + PAGE_ALIGN(bm->size)); bm->released = true; } @@ -487,15 +500,9 @@ static void *__init bootstrap_map_addr(paddr_t start, paddr_t end) return ret; } -void *__init bootstrap_map(const module_t *mod) -{ - return bootstrap_map_addr(pfn_to_paddr(mod->mod_start), - pfn_to_paddr(mod->mod_start) + mod->mod_end); -} - void *__init bootstrap_map_bm(const struct boot_module *bm) { - return bootstrap_map(bm->mod); + return bootstrap_map_addr(bm->start, bm->start + bm->size); } void __init bootstrap_unmap(void) @@ -673,8 +680,8 @@ static uint64_t __init consider_modules( for ( i = 0; i < nr_mods ; ++i ) { - uint64_t start = pfn_to_paddr(mods[i].mod->mod_start); - uint64_t end = start + PAGE_ALIGN(mods[i].mod->mod_end); + uint64_t start = mods[i].start; + uint64_t end = start + PAGE_ALIGN(mods[i].size); if ( i == this_mod ) continue; @@ -1405,13 +1412,9 @@ void asmlinkage __init noreturn __start_xen(void) set_kexec_crash_area_size((u64)nr_pages << PAGE_SHIFT); kexec_reserve_area(); - for ( i = 0; !efi_enabled(EFI_LOADER) && i < bi->nr_modules; i++ ) - { - if ( bi->mods[i].mod->mod_start & (PAGE_SIZE - 1) ) + for ( i = 0; i < bi->nr_modules; i++ ) + if ( bi->mods[i].start & (PAGE_SIZE - 1) ) panic("Bootloader didn't honor module alignment request\n"); - bi->mods[i].mod->mod_end -= bi->mods[i].mod->mod_start; - bi->mods[i].mod->mod_start >>= PAGE_SHIFT; - } /* * TODO: load ucode earlier once multiboot modules become accessible @@ -1430,13 +1433,12 @@ void asmlinkage __init noreturn __start_xen(void) * respective reserve_e820_ram() invocation below. No need to * query efi_boot_mem_unused() here, though. */ - xen->mod->mod_start = virt_to_mfn(_stext); - xen->mod->mod_end = __2M_rwdata_end - _stext; + xen->start = virt_to_maddr(_stext); + xen->size = __2M_rwdata_end - _stext; } bi->mods[0].headroom = - bzimage_headroom(bootstrap_map_bm(&bi->mods[0]), - bi->mods[0].mod->mod_end); + bzimage_headroom(bootstrap_map_bm(&bi->mods[0]), bi->mods[0].size); bootstrap_unmap(); #ifndef highmem_start @@ -1517,7 +1519,7 @@ void asmlinkage __init noreturn __start_xen(void) for ( j = bi->nr_modules - 1; j >= 0; j-- ) { struct boot_module *bm = &bi->mods[j]; - unsigned long size = PAGE_ALIGN(bm->headroom + bm->mod->mod_end); + unsigned long size = PAGE_ALIGN(bm->headroom + bm->size); if ( bm->relocated ) continue; @@ -1529,14 +1531,11 @@ void asmlinkage __init noreturn __start_xen(void) if ( highmem_start && end > highmem_start ) continue; - if ( s < end && - (bm->headroom || - ((end - size) >> PAGE_SHIFT) > bm->mod->mod_start) ) + if ( s < end && (bm->headroom || (end - size) > bm->start) ) { - move_memory(end - size + bm->headroom, - pfn_to_paddr(bm->mod->mod_start), bm->mod->mod_end); - bm->mod->mod_start = (end - size) >> PAGE_SHIFT; - bm->mod->mod_end += bm->headroom; + move_memory(end - size + bm->headroom, bm->start, bm->size); + bm->start = (end - size); + bm->size += bm->headroom; bm->relocated = true; } } @@ -1567,10 +1566,9 @@ void asmlinkage __init noreturn __start_xen(void) panic("Not enough memory to relocate the dom0 kernel image\n"); for ( i = 0; i < bi->nr_modules; ++i ) { - const struct boot_module *bm = &bi->mods[i]; - uint64_t s = pfn_to_paddr(bm->mod->mod_start); + uint64_t s = bi->mods[i].start, l = bi->mods[i].size; - reserve_e820_ram(&boot_e820, s, s + PAGE_ALIGN(bm->mod->mod_end)); + reserve_e820_ram(&boot_e820, s, s + PAGE_ALIGN(l)); } if ( !xen_phys_start ) @@ -1648,8 +1646,7 @@ void asmlinkage __init noreturn __start_xen(void) map_e = boot_e820.map[j].addr + boot_e820.map[j].size; for ( j = 0; j < bi->nr_modules; ++j ) { - uint64_t end = pfn_to_paddr(bi->mods[j].mod->mod_start) + - bi->mods[j].mod->mod_end; + uint64_t end = bi->mods[j].start + bi->mods[j].size; if ( map_e < end ) map_e = end; @@ -1723,13 +1720,11 @@ void asmlinkage __init noreturn __start_xen(void) for ( i = 0; i < bi->nr_modules; ++i ) { - const struct boot_module *bm = &bi->mods[i]; + unsigned long s = bi->mods[i].start, l = bi->mods[i].size; - set_pdx_range(bm->mod->mod_start, - bm->mod->mod_start + PFN_UP(bm->mod->mod_end)); - map_pages_to_xen((unsigned long)mfn_to_virt(bm->mod->mod_start), - _mfn(bm->mod->mod_start), - PFN_UP(bm->mod->mod_end), PAGE_HYPERVISOR); + set_pdx_range(paddr_to_pfn(s), paddr_to_pfn(s + l) + 1); + map_pages_to_xen((unsigned long)maddr_to_virt(s), maddr_to_mfn(s), + PFN_UP(l), PAGE_HYPERVISOR); } #ifdef CONFIG_KEXEC diff --git a/xen/xsm/xsm_policy.c b/xen/xsm/xsm_policy.c index 76280903d5..7f70d860bd 100644 --- a/xen/xsm/xsm_policy.c +++ b/xen/xsm/xsm_policy.c @@ -43,7 +43,7 @@ int __init xsm_multiboot_policy_init( struct boot_module *bm = &bi->mods[i]; _policy_start = bootstrap_map_bm(bm); - _policy_len = bm->mod->mod_end; + _policy_len = bm->size; if ( (xsm_magic_t)(*_policy_start) == XSM_MAGIC ) { From 22d9e75944bd9bbbd7e28cdbc12301cf0ed60533 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Tue, 19 Nov 2024 13:43:17 -0800 Subject: [PATCH 09/46] misra: increase identifiers length to 63 and align doc with ECLAIR config Currently the identifiers characters limit is arbitrarily set to 40. It causes a few violations as we have some identifiers longer than 40. Increase the limit to another rather arbitrary limit of 63. Thanks to this change, we remove a few violations, getting us one step closer to marking Rules 5.2 and 5.4 as clean. The ECLAIR configuration is already using 63, so this change matches the rules.rst documentation with the ECLAIR behavior. Signed-off-by: Stefano Stabellini Reviewed-by: Nicola Vetrini Acked-by: Jan Beulich --- docs/misra/rules.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/misra/rules.rst b/docs/misra/rules.rst index 4a144da8d6..e7763795b8 100644 --- a/docs/misra/rules.rst +++ b/docs/misra/rules.rst @@ -154,7 +154,7 @@ maintainers if you want to suggest a change. * - `Rule 5.1 `_ - Required - External identifiers shall be distinct - - The Xen characters limit for identifiers is 40. Public headers + - The Xen characters limit for identifiers is 63. Public headers (xen/include/public/) are allowed to retain longer identifiers for backward compatibility. @@ -162,7 +162,7 @@ maintainers if you want to suggest a change. - Required - Identifiers declared in the same scope and name space shall be distinct - - The Xen characters limit for identifiers is 40. Public headers + - The Xen characters limit for identifiers is 63. Public headers (xen/include/public/) are allowed to retain longer identifiers for backward compatibility. @@ -177,7 +177,7 @@ maintainers if you want to suggest a change. * - `Rule 5.4 `_ - Required - Macro identifiers shall be distinct - - The Xen characters limit for macro identifiers is 40. Public + - The Xen characters limit for macro identifiers is 63. Public headers (xen/include/public/) are allowed to retain longer identifiers for backward compatibility. From 96efb13459f16b9e57fd39902c3c0ecb0aad6633 Mon Sep 17 00:00:00 2001 From: Michal Orzel Date: Tue, 19 Nov 2024 12:51:41 +0100 Subject: [PATCH 10/46] bootfdt: Unify early printing of memory ranges endpoints At the moment, when printing memory ranges during early boot, endpoints of some ranges are printed as inclusive (RAM, RESVD, SHMEM) and some as exclusive (Initrd, MODULE). Make the behavior consistent and print all the endpoints as inclusive. Signed-off-by: Michal Orzel Reviewed-by: Luca Fancellu Acked-by: Stefano Stabellini --- xen/common/device-tree/bootfdt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xen/common/device-tree/bootfdt.c b/xen/common/device-tree/bootfdt.c index 927f59c64b..480644b4b4 100644 --- a/xen/common/device-tree/bootfdt.c +++ b/xen/common/device-tree/bootfdt.c @@ -439,7 +439,7 @@ static int __init process_chosen_node(const void *fdt, int node, return -EINVAL; } - printk("Initrd %"PRIpaddr"-%"PRIpaddr"\n", start, end); + printk("Initrd %"PRIpaddr"-%"PRIpaddr"\n", start, end - 1); add_boot_module(BOOTMOD_RAMDISK, start, end-start, false); @@ -524,7 +524,7 @@ static void __init early_print_info(void) printk("MODULE[%d]: %"PRIpaddr" - %"PRIpaddr" %-12s\n", i, mods->module[i].start, - mods->module[i].start + mods->module[i].size, + mods->module[i].start + mods->module[i].size - 1, boot_module_kind_as_string(mods->module[i].kind)); for ( i = 0; i < mem_resv->nr_banks; i++ ) From 5726d8e5ef1852be90c9c05f08259b6a4f0ebb5e Mon Sep 17 00:00:00 2001 From: Anthony PERARD Date: Tue, 19 Nov 2024 10:15:27 +0000 Subject: [PATCH 11/46] CI: Remove deprecated "only:variables" in favor of "rules:if" Also, this prevent using "rules", like in the ".test-jobs-common" template. https://docs.gitlab.com/ee/ci/yaml/#only--except Signed-off-by: Anthony PERARD Reviewed-by: Stefano Stabellini --- automation/gitlab-ci/test.yaml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/automation/gitlab-ci/test.yaml b/automation/gitlab-ci/test.yaml index f5dd4de757..ab5c8be0cd 100644 --- a/automation/gitlab-ci/test.yaml +++ b/automation/gitlab-ci/test.yaml @@ -98,9 +98,8 @@ - '*.log' - '*.dtb' when: always - only: - variables: - - $XILINX_JOBS == "true" && $CI_COMMIT_REF_PROTECTED == "true" + rules: + - if: $XILINX_JOBS == "true" && $CI_COMMIT_REF_PROTECTED == "true" tags: - xilinx @@ -117,9 +116,8 @@ - smoke.serial - '*.log' when: always - only: - variables: - - $XILINX_JOBS == "true" && $CI_COMMIT_REF_PROTECTED == "true" + rules: + - if: $XILINX_JOBS == "true" && $CI_COMMIT_REF_PROTECTED == "true" tags: - xilinx @@ -137,9 +135,8 @@ - smoke.serial - '*.log' when: always - only: - variables: - - $QUBES_JOBS == "true" && $CI_COMMIT_REF_PROTECTED == "true" + rules: + - if: $QUBES_JOBS == "true" && $CI_COMMIT_REF_PROTECTED == "true" tags: - qubes-hw2 From a231538acdeb8cf11a7420de9496815e6bd44bb0 Mon Sep 17 00:00:00 2001 From: Anthony PERARD Date: Tue, 19 Nov 2024 10:15:27 +0000 Subject: [PATCH 12/46] CI: Define XEN_REGISTRY variable This allow to change the registry used for container in a single place, and could be controlled via other mean. Signed-off-by: Anthony PERARD Reviewed-by: Stefano Stabellini --- .gitlab-ci.yml | 3 +++ automation/gitlab-ci/build.yaml | 4 ++-- automation/gitlab-ci/test.yaml | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ef4484e09a..941e5822e8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,3 +1,6 @@ +variables: + XEN_REGISTRY: registry.gitlab.com/xen-project/xen + workflow: rules: - if: $CI_COMMIT_BRANCH =~ /^(master|smoke|^coverity-tested\/.*|stable-.*)$/ diff --git a/automation/gitlab-ci/build.yaml b/automation/gitlab-ci/build.yaml index ce39b0ee21..1ca6764225 100644 --- a/automation/gitlab-ci/build.yaml +++ b/automation/gitlab-ci/build.yaml @@ -1,6 +1,6 @@ .build-tmpl: &build stage: build - image: registry.gitlab.com/xen-project/xen/${CONTAINER} + image: ${XEN_REGISTRY}/${CONTAINER} script: - ./automation/scripts/build 2>&1 | tee build.log artifacts: @@ -208,7 +208,7 @@ .yocto-test: stage: build - image: registry.gitlab.com/xen-project/xen/${CONTAINER} + image: ${XEN_REGISTRY}/${CONTAINER} script: - ./automation/build/yocto/build-yocto.sh -v --log-dir=./logs --xen-dir=`pwd` ${YOCTO_BOARD} ${YOCTO_OUTPUT} variables: diff --git a/automation/gitlab-ci/test.yaml b/automation/gitlab-ci/test.yaml index ab5c8be0cd..1822e3ea5f 100644 --- a/automation/gitlab-ci/test.yaml +++ b/automation/gitlab-ci/test.yaml @@ -1,6 +1,6 @@ .test-jobs-common: stage: test - image: registry.gitlab.com/xen-project/xen/${CONTAINER} + image: ${XEN_REGISTRY}/${CONTAINER} .arm64-test-needs: &arm64-test-needs - alpine-3.18-arm64-rootfs-export From 5cc971a4bf5891d0b68782e92c65015a62dcc990 Mon Sep 17 00:00:00 2001 From: Anthony PERARD Date: Tue, 19 Nov 2024 10:15:28 +0000 Subject: [PATCH 13/46] CI: New stage "containers" to rebuild some containers Rebuild rolling release containers when XEN_CI_REBUILD_CONTAINERS is set. This is to be use with a scheduled pipeline. Signed-off-by: Anthony PERARD Reviewed-by: Stefano Stabellini --- .gitlab-ci.yml | 16 ++++++++++++--- automation/gitlab-ci/containers.yaml | 29 ++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 automation/gitlab-ci/containers.yaml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 941e5822e8..5a9b8b7228 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -8,11 +8,21 @@ workflow: - when: always stages: + - containers - analyze - build - test include: - - 'automation/gitlab-ci/analyze.yaml' - - 'automation/gitlab-ci/build.yaml' - - 'automation/gitlab-ci/test.yaml' + - local: 'automation/gitlab-ci/containers.yaml' + rules: + - if: $XEN_CI_REBUILD_CONTAINERS + - local: 'automation/gitlab-ci/analyze.yaml' + rules: + - if: $XEN_CI_REBUILD_CONTAINERS == null + - local: 'automation/gitlab-ci/build.yaml' + rules: + - if: $XEN_CI_REBUILD_CONTAINERS == null + - local: 'automation/gitlab-ci/test.yaml' + rules: + - if: $XEN_CI_REBUILD_CONTAINERS == null diff --git a/automation/gitlab-ci/containers.yaml b/automation/gitlab-ci/containers.yaml new file mode 100644 index 0000000000..25e8bdc34b --- /dev/null +++ b/automation/gitlab-ci/containers.yaml @@ -0,0 +1,29 @@ +.container-build-tmpl: + stage: containers + image: docker:stable + tags: + - container-builder + rules: + - if: $XEN_CI_REBUILD_CONTAINERS + services: + - docker:dind + before_script: + - apk add make + - docker info + - docker login -u $CI_DEPLOY_USER -p $CI_DEPLOY_PASSWORD $CI_REGISTRY + script: + - make -C automation/build PUSH=1 REGISTRY=${XEN_REGISTRY} ${CONTAINER/:/\/} + after_script: + - docker logout + +container-archlinux-current: + extends: + - .container-build-tmpl + variables: + CONTAINER: "archlinux:current" + +container-opensuse-tumbleweed-x86_64: + extends: + - .container-build-tmpl + variables: + CONTAINER: "opensuse:tumbleweed-x86_64" From e36ed9975233228a9a075960e7a9c3f3fb9a2e5f Mon Sep 17 00:00:00 2001 From: Fedora developers Date: Mon, 8 Jul 2024 13:35:51 +0200 Subject: [PATCH 14/46] QUBESOS: xen.efi.build --- xen/arch/x86/arch.mk | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xen/arch/x86/arch.mk b/xen/arch/x86/arch.mk index 9dde8a5756..1e2caa2f3e 100644 --- a/xen/arch/x86/arch.mk +++ b/xen/arch/x86/arch.mk @@ -95,7 +95,9 @@ XEN_BUILD_EFI := $(call if-success,$(CC) $(filter-out -include %/include/xen/con -c $(srctree)/$(efi-check).c -o $(efi-check).o,y) # Check if the linker supports PE. -EFI_LDFLAGS := $(patsubst -m%,-mi386pep,$(LDFLAGS)) --subsystem=10 --enable-long-section-names +#EFI_LDFLAGS := $(patsubst -m%,-mi386pep,$(LDFLAGS)) --subsystem=10 --enable-long-section-names +# use a reduced set of options from LDFLAGS +EFI_LDFLAGS = --as-needed --build-id=sha1 -mi386pep --subsystem=10 --enable-long-section-names LD_PE_check_cmd = $(call ld-option,$(EFI_LDFLAGS) --image-base=0x100000000 -o $(efi-check).efi $(efi-check).o) XEN_BUILD_PE := $(LD_PE_check_cmd) From 11aee1127ff14acb08d066a3a123760ddcbbe8c3 Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Fri, 8 Nov 2024 16:21:44 +0100 Subject: [PATCH 15/46] QUBESOS: x86/boot/Makefile: align text_diff to 0x40 bytes This is the file alignment when building Xen through Qubes builder. Signed-off-by: Krystian Hebel --- xen/arch/x86/boot/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xen/arch/x86/boot/Makefile b/xen/arch/x86/boot/Makefile index d457876659..607eb431d0 100644 --- a/xen/arch/x86/boot/Makefile +++ b/xen/arch/x86/boot/Makefile @@ -41,7 +41,7 @@ LD32 := $(LD) $(subst x86_64,i386,$(LDFLAGS_DIRECT)) # is greater than 2^16 so that any 16bit relocations if present in the object # file turns into a build-time error. text_gap := 0x010200 -text_diff := 0x408020 +text_diff := 0x408040 $(obj)/build32.base.lds: AFLAGS-y += -DGAP=$(text_gap) -DTEXT_DIFF=$(text_diff) $(obj)/build32.offset.lds: AFLAGS-y += -DGAP=$(text_gap) -DTEXT_DIFF=$(text_diff) -DAPPLY_OFFSET From 69b517e8850730ad51185b17b07119ba14a02e46 Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Wed, 6 Nov 2024 14:09:45 +0100 Subject: [PATCH 16/46] .github/workflows/coverity.yml: remove file This is expecting upstream's credentials, we don't have them. Remove the file to avoid errors. Signed-off-by: Krystian Hebel --- .github/workflows/coverity.yml | 55 ---------------------------------- 1 file changed, 55 deletions(-) delete mode 100644 .github/workflows/coverity.yml diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml deleted file mode 100644 index a6c2819b0a..0000000000 --- a/.github/workflows/coverity.yml +++ /dev/null @@ -1,55 +0,0 @@ -name: Coverity Scan - -# We only want to test official release code, not every pull request. -on: - workflow_dispatch: - schedule: - - cron: '18 9 * * WED,SUN' # Bi-weekly at 9:18 UTC - -jobs: - coverity: - runs-on: ubuntu-24.04 - steps: - - name: Install build dependencies - run: | - sudo apt-get update - sudo apt-get install -y \ - build-essential \ - git-core \ - golang \ - iasl \ - libbz2-dev \ - libext2fs-dev \ - liblzma-dev \ - libncurses5-dev \ - libyajl-dev \ - libzstd-dev \ - ocaml \ - ocaml-findlib \ - python3-dev \ - uuid-dev \ - zlib1g-dev \ - - - uses: actions/checkout@v4 - with: - ref: staging - - - name: Configure Xen - run: | - ./configure \ - --disable-docs \ - --disable-stubdom \ - --with-system-qemu=/bin/true \ - --with-system-seabios=/bin/true \ - --with-system-ovmf=/bin/true \ - - - name: Pre build stuff - run: | - make -j`nproc` mini-os-dir - - - uses: vapier/coverity-scan-action@v1 - with: - command: make -j`nproc` build-xen build-tools && make -j`nproc` -C extras/mini-os/ - project: XenProject - email: ${{ secrets.COVERITY_SCAN_EMAIL }} - token: ${{ secrets.COVERITY_SCAN_TOKEN }} From b546c086db83807890008b0ae0432f8367929c4e Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Mon, 28 Oct 2024 18:18:23 +0100 Subject: [PATCH 17/46] CI: add files for qubes-builder Signed-off-by: Krystian Hebel --- qubesos_xen.logrotate | 9 + qubesos_xen.modules-load.conf | 9 + qubesos_xen_config | 154 ++++++ vmm-xen.spec.in | 952 ++++++++++++++++++++++++++++++++++ 4 files changed, 1124 insertions(+) create mode 100644 qubesos_xen.logrotate create mode 100644 qubesos_xen.modules-load.conf create mode 100644 qubesos_xen_config create mode 100644 vmm-xen.spec.in diff --git a/qubesos_xen.logrotate b/qubesos_xen.logrotate new file mode 100644 index 0000000000..6bf2ae091a --- /dev/null +++ b/qubesos_xen.logrotate @@ -0,0 +1,9 @@ +/var/log/xen/xen-hotplug.log +/var/log/xen/domain-builder-ng.log +/var/log/xen/console/*.log{ + notifempty + missingok + compress + copytruncate + su root qubes +} diff --git a/qubesos_xen.modules-load.conf b/qubesos_xen.modules-load.conf new file mode 100644 index 0000000000..2585265bff --- /dev/null +++ b/qubesos_xen.modules-load.conf @@ -0,0 +1,9 @@ +xen-evtchn +xen-gntdev +xen-gntalloc +xen-blkback +xen-pciback +xen-privcmd +xen-acpi-processor +# Not used in Qubes dom0 +#xen-netback diff --git a/qubesos_xen_config b/qubesos_xen_config new file mode 100644 index 0000000000..4bebb459df --- /dev/null +++ b/qubesos_xen_config @@ -0,0 +1,154 @@ +# +# Automatically generated file; DO NOT EDIT. +# Xen/x86 4.17.3 Configuration +# +CONFIG_CC_IS_GCC=y +CONFIG_GCC_VERSION=120301 +CONFIG_CLANG_VERSION=0 +CONFIG_LD_IS_GNU=y +CONFIG_CC_HAS_VISIBILITY_ATTRIBUTE=y +CONFIG_X86_64=y +CONFIG_X86=y +CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig" +CONFIG_CC_HAS_INDIRECT_THUNK=y +CONFIG_HAS_AS_CET_SS=y +CONFIG_HAS_CC_CET_IBT=y + +# +# Architecture Features +# +CONFIG_64BIT=y +CONFIG_NR_CPUS=256 +CONFIG_PV=y +# CONFIG_PV32 is not set +# CONFIG_PV_LINEAR_PT is not set +CONFIG_HVM=y +CONFIG_XEN_SHSTK=y +CONFIG_XEN_IBT=y +# CONFIG_SHADOW_PAGING is not set +# CONFIG_BIGMEM is not set +# CONFIG_HVM_FEP is not set +CONFIG_TBOOT=y +CONFIG_XEN_ALIGN_DEFAULT=y +# CONFIG_XEN_ALIGN_2M is not set +# CONFIG_X2APIC_PHYSICAL is not set +# CONFIG_X2APIC_CLUSTER is not set +CONFIG_X2APIC_MIXED=y +# CONFIG_XEN_GUEST is not set +# CONFIG_HYPERV_GUEST is not set +# CONFIG_MEM_PAGING is not set +# CONFIG_MEM_SHARING is not set +# end of Architecture Features + +# +# Common Features +# +CONFIG_COMPAT=y +CONFIG_CORE_PARKING=y +CONFIG_GRANT_TABLE=y +CONFIG_ALTERNATIVE_CALL=y +CONFIG_ARCH_MAP_DOMAIN_PAGE=y +CONFIG_HAS_ALTERNATIVE=y +CONFIG_HAS_COMPAT=y +CONFIG_HAS_DIT=y +CONFIG_HAS_EX_TABLE=y +CONFIG_HAS_FAST_MULTIPLY=y +CONFIG_HAS_IOPORTS=y +CONFIG_HAS_KEXEC=y +CONFIG_HAS_PDX=y +CONFIG_HAS_SCHED_GRANULARITY=y +CONFIG_HAS_UBSAN=y +CONFIG_MEM_ACCESS_ALWAYS_ON=y +CONFIG_MEM_ACCESS=y +CONFIG_NEEDS_LIBELF=y +CONFIG_NUMA=y + +# +# Speculative hardening +# +CONFIG_INDIRECT_THUNK=y +CONFIG_SPECULATIVE_HARDEN_ARRAY=y +CONFIG_SPECULATIVE_HARDEN_BRANCH=y +CONFIG_SPECULATIVE_HARDEN_GUEST_ACCESS=y +CONFIG_SPECULATIVE_HARDEN_LOCK=y +# end of Speculative hardening + +CONFIG_DIT_DEFAULT=y +CONFIG_HYPFS=y +CONFIG_HYPFS_CONFIG=y +CONFIG_IOREQ_SERVER=y +# CONFIG_KEXEC is not set +CONFIG_EFI_SET_VIRTUAL_ADDRESS_MAP=y +CONFIG_XENOPROF=y +# CONFIG_XSM is not set +# CONFIG_ARGO is not set + +# +# Schedulers +# +CONFIG_SCHED_CREDIT=y +CONFIG_SCHED_CREDIT2=y +CONFIG_SCHED_RTDS=y +# CONFIG_SCHED_ARINC653 is not set +CONFIG_SCHED_NULL=y +# CONFIG_SCHED_CREDIT_DEFAULT is not set +CONFIG_SCHED_CREDIT2_DEFAULT=y +# CONFIG_SCHED_RTDS_DEFAULT is not set +# CONFIG_SCHED_NULL_DEFAULT is not set +CONFIG_SCHED_DEFAULT="credit2" +# end of Schedulers + +CONFIG_CRYPTO=y +# CONFIG_LIVEPATCH is not set +# CONFIG_ENFORCE_UNIQUE_SYMBOLS is not set +CONFIG_SUPPRESS_DUPLICATE_SYMBOL_WARNINGS=y +CONFIG_CMDLINE="ept=exec-sp spec-ctrl=unpriv-mmio" +# CONFIG_CMDLINE_OVERRIDE is not set +CONFIG_DOM0_MEM="min:1024M,max:4096M" +# CONFIG_TRACEBUFFER is not set +# end of Common Features + +# +# Device Drivers +# +CONFIG_ACPI=y +CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y +CONFIG_ACPI_NUMA=y +CONFIG_HAS_NS16550=y +CONFIG_HAS_EHCI=y +CONFIG_SERIAL_TX_BUFSIZE=16384 +CONFIG_XHCI=y +CONFIG_HAS_CPUFREQ=y +CONFIG_HAS_PASSTHROUGH=y +# CONFIG_IOMMU_QUARANTINE_NONE is not set +CONFIG_IOMMU_QUARANTINE_BASIC=y +# CONFIG_IOMMU_QUARANTINE_SCRATCH_PAGE is not set +CONFIG_HAS_PCI=y +CONFIG_HAS_PCI_MSI=y +CONFIG_VIDEO=y +CONFIG_VGA=y +CONFIG_HAS_VPCI=y +# end of Device Drivers + +CONFIG_EXPERT=y +CONFIG_UNSUPPORTED=y +CONFIG_ARCH_SUPPORTS_INT128=y + +# +# Debugging Options +# +# CONFIG_DEBUG is not set +# CONFIG_CRASH_DEBUG is not set +CONFIG_GDBSX=y +CONFIG_DEBUG_INFO=y +# CONFIG_FRAME_POINTER is not set +# CONFIG_COVERAGE is not set +# CONFIG_DEBUG_LOCK_PROFILE is not set +# CONFIG_DEBUG_LOCKS is not set +# CONFIG_PERF_COUNTERS is not set +# CONFIG_VERBOSE_DEBUG is not set +CONFIG_SCRUB_DEBUG=y +# CONFIG_UBSAN is not set +# CONFIG_DEBUG_TRACE is not set +# CONFIG_XMEM_POOL_POISON is not set +# end of Debugging Options diff --git a/vmm-xen.spec.in b/vmm-xen.spec.in new file mode 100644 index 0000000000..efce33c80e --- /dev/null +++ b/vmm-xen.spec.in @@ -0,0 +1,952 @@ +# Build ocaml bits unless rpmbuild was run with --without ocaml +# or ocamlopt is missing (the xen makefile doesn't build ocaml bits if it isn't there) +%define with_ocaml 0 +%define build_ocaml 0 +# Build with docs unless rpmbuild was run with --without docs +%define build_docs %{?_without_docs: 0} %{?!_without_docs: 1} +# Build without stubdom unless rpmbuild was run with --with stubdom +%define build_stubdom %{?_with_stubdom: 1} %{?!_with_stubdom: 0} +# Build without qemu-traditional unless rpmbuild was run with --with qemutrad +%define build_qemutrad %{?_with_qemutrad: 1} %{?!_with_qemutrad: 0} +# build with ovmf from edk2-ovmf unless rpmbuild was run with --without ovmf +%define build_ovmf %{?_without_ovmf: 0} %{?!_without_ovmf: 1} +# set to 0 for archs that don't use qemu or ovmf (reduces build dependencies) +%ifnarch x86_64 %{ix86} +%define build_qemutrad 0 +%define build_ovmf 0 +%endif +%if ! %build_qemutrad +%define build_stubdom 0 +%endif +# Build with xen hypervisor unless rpmbuild was run with --without hyp +%define build_hyp %{?_without_hyp: 0} %{?!_without_hyp: 1} +# build xsm support unless rpmbuild was run with --without xsm +# or required packages are missing +%define with_xsm 0 +%define build_xsm 0 +# cross compile 64-bit hypervisor on ix86 unless rpmbuild was run +# with --without crosshyp +%define build_crosshyp %{?_without_crosshyp: 0} %{?!_without_crosshyp: 1} +%ifnarch %{ix86} +%define build_crosshyp 0 +%else +%if ! %build_crosshyp +%define build_hyp 0 +%endif +%endif +# no point in trying to build xsm on ix86 without a hypervisor +%if ! %build_hyp +%define build_xsm 0 +%endif +# build an efi boot image (where supported) unless rpmbuild was run with +# --without efi +%define build_efi 1 +# xen only supports efi boot images on x86_64 or aarch64 +# i686 builds a x86_64 hypervisor so add that as well +%ifnarch x86_64 aarch64 %{ix86} +%define build_efi 0 +%endif +%if "%dist" >= ".fc20" +%define with_systemd_presets 1 +%else +%define with_systemd_presets 0 +%endif + +# workaround for https://bugzilla.redhat.com/1671883 (dwz leaving temp files of +# hardlinked sources) +%define _unpackaged_files_terminate_build 0 + +# xen.efi.elf doesn't have proper build-id +%define _missing_build_ids_terminate_build 0 + +# Hypervisor ABI +%define hv_abi 4.19 + +%define upstream_version @VERSION@ +%define rctag %(echo @VERSION@ | sed -n -e 's/.*-\\(rc[0-9]*\\).*/0.\\1./;/rc/p') + +Summary: Xen is a virtual machine monitor +Name: xen +Version: %(echo @VERSION@ | sed 's/-rc.*//') +Release: %{?rctag}@REL@%{?dist} +Epoch: 2001 +License: GPLv2+ and LGPLv2+ and BSD +URL: http://xen.org/ +Source0: %{name}-%{version}.tar.gz +Source4: qubesos_xen_config +Source2: qubesos_xen.logrotate +Source3: qubesos_xen.modules-load.conf +Provides: xen-gvt + +# This fixes building .efi file. While it isn't used (even on UEFI) in the final +# system, keep it to create RPMs similar to the original ones. +# TODO: these are included as commits right now for easier conflict resolution, +# but ultimately they should be part of Qubes patches, not upstream Xen +#Patch0203: qubesos_0203-xen.efi.build.patch +#Patch1019: qubesos_1019-x86-boot-Makefile-align-text_diff-to-0x40-bytes.patch + +%if %build_qemutrad +BuildRequires: libidn-devel zlib-devel SDL-devel curl-devel +BuildRequires: libX11-devel gtk2-devel libaio-devel +%endif +# build using Fedora seabios and ipxe packages for roms +BuildRequires: seabios-bin ipxe-roms-qemu +%ifarch %{ix86} x86_64 +# for the VMX "bios" +BuildRequires: dev86 +%endif +BuildRequires: python%{python3_pkgversion}-devel ncurses-devel python%{python3_pkgversion}-setuptools +BuildRequires: perl-interpreter perl-generators +# BEGIN QUBES SPECIFIC PART +BuildRequires: autoconf +BuildRequires: automake +# END QUBES SPECIFIC PART +BuildRequires: gettext +BuildRequires: zlib-devel +# Several tools now use uuid +BuildRequires: libuuid-devel +# iasl needed to build hvmloader +BuildRequires: acpica-tools +# modern compressed kernels +BuildRequires: bzip2-devel xz-devel libzstd-devel +# BEGIN QUBES SPECIFIC PART +## libfsimage +#BuildRequires: e2fsprogs-devel +# tools now require yajl and wget +BuildRequires: yajl-devel +# END QUBES SPECIFIC PART +# remus support now needs libnl3 +BuildRequires: libnl3-devel +%if %with_xsm +# xsm policy file needs needs checkpolicy and m4 +BuildRequires: checkpolicy m4 +%endif +%if %build_crosshyp +# cross compiler for building 64-bit hypervisor on ix86 +BuildRequires: gcc-x86_64-linux-gnu +%endif +BuildRequires: gcc make +Requires: iproute +Requires: python%{python3_pkgversion}-lxml +Requires: xen-runtime = %{epoch}:%{version}-%{release} +# Not strictly a dependency, but kpartx is by far the most useful tool right +# now for accessing domU data from within a dom0 so bring it in when the user +# installs xen. +Requires: kpartx +ExclusiveArch: x86_64 aarch64 +#ExclusiveArch: %#{ix86} x86_64 ia64 noarch +%if %with_ocaml +BuildRequires: ocaml, ocaml-findlib +BuildRequires: perl(Data::Dumper) +%endif +%if %with_systemd_presets +Requires(post): systemd +Requires(preun): systemd +BuildRequires: systemd +%endif +BuildRequires: systemd-devel +%ifarch armv7hl aarch64 +BuildRequires: libfdt-devel +%endif +%if %build_ovmf +BuildRequires: edk2-ovmf +%endif +%if %build_hyp +BuildRequires: bison flex +%endif +BuildRequires: rsync + +%description +This package contains the XenD daemon and xm command line +tools, needed to manage virtual machines running under the +Xen hypervisor + +# BEGIN QUBES SPECIFIC PART +%package -n python%{python3_pkgversion}-%{name} +Summary: python%{python3_pkgversion} bindings for Xen tools +Group: Development/Libraries +Requires: xen-libs = %{epoch}:%{version}-%{release} +Requires: python%{python3_pkgversion} +%{?python_provide:%python_provide python%{python3_pkgversion}-%{name}} + +%description -n python%{python3_pkgversion}-%{name} +This package contains python%{python3_pkgversion} bindings to Xen tools. Especially xen.lowlevel.xs +and xen.lowlevel.xc modules. +# END QUBES SPECIFIC PART + +%package libs +Summary: Libraries for Xen tools +Requires: xen-licenses +# BEGIN QUBES SPECIFIC PART +Provides: xen-gvt-libs +# toolstack <-> stubdomain API change +Conflicts: xen-hvm-stubdom-linux < 1.2.5 +Conflicts: xen-hvm-stubdom-linux-full < 1.2.5 +# libxl ABI change +Conflicts: libvirt-daemon-driver-libxl < 1000:6.6.0-7 +# END QUBES SPECIFIC PART + +%description libs +This package contains the libraries needed to run applications +which manage Xen virtual machines. + + +%package runtime +Summary: Core Xen runtime environment +Requires: xen-libs = %{epoch}:%{version}-%{release} +#Requires: /usr/bin/qemu-img /usr/bin/qemu-nbd +Requires: /usr/bin/qemu-img +# Ensure we at least have a suitable kernel installed, though we can't +# force user to actually boot it. +Requires: xen-hypervisor-abi = %{hv_abi} +# BEGIN QUBES SPECIFIC PART +# perl is used in /etc/xen/scripts/locking.sh +# Recommends: perl +%ifnarch armv7hl aarch64 +# use /usr/bin/qemu-system-i386 in Fedora instead of qemu-xen +#Recommends: qemu-system-x86-core +# rom file for qemu-xen-traditional +Recommends: ipxe-roms-qemu +%endif +Requires: seabios-bin +# END QUBES SPECIFIC PART + +%description runtime +This package contains the runtime programs and daemons which +form the core Xen userspace environment. + + +%package hypervisor +Summary: Libraries for Xen tools +Provides: xen-hypervisor-abi = %{hv_abi} +Requires: xen-licenses +%if %build_hyp +%ifarch %{ix86} +Recommends: grub2-pc-modules +%endif +%ifarch x86_64 +# BEGIN QUBES SPECIFIC PART +#Recommends: grub2-pc-modules grub2-efi-x64-modules +# END QUBES SPECIFIC PART +%endif +%endif + +%description hypervisor +This package contains the Xen hypervisor + + +%if %build_docs +%package doc +Summary: Xen documentation +BuildArch: noarch +Requires: xen-licenses +# for the docs +BuildRequires: perl(Pod::Man) perl(Pod::Text) perl(File::Find) +BuildRequires: transfig pandoc perl(Pod::Html) + +%description doc +This package contains the Xen documentation. +%endif + + +%package devel +Summary: Development libraries for Xen tools +Requires: xen-libs = %{epoch}:%{version}-%{release} +Requires: libuuid-devel + +%description devel +This package contains what's needed to develop applications +which manage Xen virtual machines. + + +%package licenses +Summary: License files from Xen source + +%description licenses +This package contains the license files from the source used +to build the xen packages. + + +%if %build_ocaml +%package ocaml +Summary: Ocaml libraries for Xen tools +Requires: ocaml-runtime, xen-libs = %{epoch}:%{version}-%{release} + +%description ocaml +This package contains libraries for ocaml tools to manage Xen +virtual machines. + + +%package ocaml-devel +Summary: Ocaml development libraries for Xen tools +Requires: xen-ocaml = %{epoch}:%{version}-%{release} + +%description ocaml-devel +This package contains libraries for developing ocaml tools to +manage Xen virtual machines. +%endif + +%prep +%autosetup -p1 -n %{name}-%{upstream_version} + +# copy xen hypervisor .config file to change settings +cp -v %{SOURCE4} xen/.config + + +%build +# This package calls binutils components directly and would need to pass +# in flags to enable the LTO plugins +# Disable LTO +%define _lto_cflags %{nil} + +%if !%build_ocaml +%define ocaml_flags OCAML_TOOLS=n +%endif +%if %build_efi +%define efi_flags EFI_VENDOR=qubes +mkdir -p dist/install/boot/efi/efi/qubes +%endif +%if %build_ocaml +mkdir -p dist/install%{_libdir}/ocaml/stublibs +%endif +# BEGIN QUBES SPECIFIC PART +EXTRA_CFLAGS_XEN_TOOLS="$RPM_OPT_FLAGS $LDFLAGS" +%if 0%{?fedora} >= 37 +EXTRA_CFLAGS_XEN_TOOLS="$EXTRA_CFLAGS_XEN_TOOLS -Wno-error=use-after-free" +%endif +export EXTRA_CFLAGS_XEN_TOOLS +# END QUBES SPECIFIC PART +export EXTRA_CFLAGS_QEMU_TRADITIONAL="$RPM_OPT_FLAGS" +export EXTRA_CFLAGS_QEMU_XEN="$RPM_OPT_FLAGS" +export PYTHON="%{__python3}" +export LDFLAGS_SAVE=`echo $LDFLAGS | sed -e 's/-Wl,//g' -e 's/,/ /g' -e 's? -specs=[-a-z/0-9]*??g'` +export CFLAGS_SAVE="$CFLAGS" +%if %build_qemutrad +CONFIG_EXTRA="--enable-qemu-traditional" +%else +CONFIG_EXTRA="" +%endif +%if %build_ovmf +CONFIG_EXTRA="$CONFIG_EXTRA --with-system-ovmf=%{_libexecdir}/%{name}/boot/ovmf.bin" +%endif +%ifnarch armv7hl aarch64 +CONFIG_EXTRA="$CONFIG_EXTRA --with-system-ipxe=/usr/share/ipxe/10ec8139.rom" +%endif +%if %(test -f /usr/share/seabios/bios-256k.bin && echo 1|| echo 0) +CONFIG_EXTRA="$CONFIG_EXTRA --with-system-seabios=/usr/share/seabios/bios-256k.bin" +%else +CONFIG_EXTRA="$CONFIG_EXTRA --disable-seabios" +%endif +./configure --prefix=%{_prefix} --libdir=%{_libdir} --libexecdir=%{_libexecdir} --with-system-qemu=/usr/bin/qemu-system-i386 --with-linux-backend-modules="xen-evtchn xen-gntdev xen-gntalloc xen-blkback xen-netback xen-pciback xen-scsiback xen-acpi-processor" --enable-systemd --disable-pygrub $CONFIG_EXTRA +unset CFLAGS CXXFLAGS FFLAGS LDFLAGS +export LDFLAGS="$LDFLAGS_SAVE" +export CFLAGS="$CFLAGS_SAVE -Wno-error=address" + +%if %build_hyp +# QUBES SPECIFIC LINE +export CFLAGS=`echo $CFLAGS | sed -e 's/-specs=\/usr\/lib\/rpm\/redhat\/redhat-annobin-cc1//g'` +%if %build_crosshyp +export CFLAGS=`echo $CFLAGS | sed -e 's/-m32//g' -e 's/-march=i686//g' 's/-specs=\/usr\/lib\/rpm\/redhat\/redhat-annobin-cc1//g'` +XEN_TARGET_ARCH=x86_64 %make_build %{?efi_flags} prefix=/usr xen CC="/usr/bin/x86_64-linux-gnu-gcc" +%else +%ifarch armv7hl +export CFLAGS=`echo $CFLAGS | sed -e 's/-mfloat-abi=hard//g' -e 's/-march=armv7-a//g'` +%endif +# armv7hl aarch64 or x86_64 +%make_build %{?efi_flags} prefix=/usr xen +%endif +%endif +unset CFLAGS CXXFLAGS FFLAGS LDFLAGS + +# BEGIN QUBES SPECIFIC PART +%ifnarch armv7hl aarch64 +#CONFIG_EXTRA="$CONFIG_EXTRA --with-system-ipxe=/usr/share/ipxe" +CONFIG_EXTRA="$CONFIG_EXTRA --disable-ipxe --disable-rombios" +CONFIG_EXTRA="$CONFIG_EXTRA --disable-pvshim" +%endif +CONFIG_EXTRA="$CONFIG_EXTRA --with-system-qemu=/usr/bin/qemu-system-x86_64" +export PATH="/usr/bin:$PATH" +autoreconf -i +# END QUBES SPECIFIC PART + +%make_build %{?ocaml_flags} prefix=/usr tools +%if %build_docs +make prefix=/usr docs +%endif +export RPM_OPT_FLAGS_RED=`echo $RPM_OPT_FLAGS | sed -e 's/-m64//g' -e 's/--param=ssp-buffer-size=4//g' -e's/-fstack-protector-strong//'` +%ifarch %{ix86} +export EXTRA_CFLAGS_XEN_TOOLS="$RPM_OPT_FLAGS_RED" +%endif +%if %build_stubdom +%ifnarch armv7hl aarch64 +make mini-os-dir +make -C stubdom build +%endif +%ifarch x86_64 +export EXTRA_CFLAGS_XEN_TOOLS="$RPM_OPT_FLAGS_RED" +XEN_TARGET_ARCH=x86_32 make -C stubdom pv-grub-if-enabled +%endif +%endif + + +%install +rm -rf %{buildroot} +mkdir -p %{buildroot} +# copy all while preserving hardlinks between files +rsync -aH dist/install/ %{buildroot}/ +%if %build_stubdom +%ifnarch armv7hl aarch64 +make DESTDIR=%{buildroot} %{?ocaml_flags} prefix=/usr install-stubdom +%endif +%endif +%if %build_efi +# BEGIN QUBES SPECIFIC PART +mkdir -p %{buildroot}/boot/efi/efi/qubes +# END QUBES SPECIFIC PART +mv %{buildroot}/boot/efi/efi %{buildroot}/boot/efi/EFI +%endif +%if %build_xsm +# policy file should be in /boot/flask +mkdir %{buildroot}/boot/flask +mv %{buildroot}/boot/xenpolicy* %{buildroot}/boot/flask +%else +rm -f %{buildroot}/boot/xenpolicy* +# BEGIN QUBES SPECIFIC PART +rm -f %{buildroot}/usr/sbin/flask-* +# END QUBES SPECIFIC PART +%endif + +############ debug packaging: list files ############ + +find %{buildroot} -print | xargs ls -ld | sed -e 's|.*%{buildroot}||' > f1.list + +############ kill unwanted stuff ############ + +# stubdom: newlib +rm -rf %{buildroot}/usr/*-xen-elf + +# hypervisor symlinks +rm -rf %{buildroot}/boot/xen-%{hv_abi}.gz +rm -rf %{buildroot}/boot/xen-4.gz +rm -rf %{buildroot}/boot/xen.gz +%if !%build_hyp +rm -rf %{buildroot}/boot +%endif + +# silly doc dir fun +rm -fr %{buildroot}%{_datadir}/doc/xen +# BEGIN QUBES SPECIFIC PART +rm -rf %{buildroot}%{_datadir}/doc/qemu +# END QUBES SPECIFIC PART + +# Pointless helper +rm -f %{buildroot}%{_sbindir}/xen-python-path + +# qemu stuff (unused or available from upstream) +rm -rf %{buildroot}/usr/share/xen/man +rm -rf %{buildroot}/usr/bin/qemu-*-xen +# BEGIN QUBES SPECIFIC PART +# ln -s qemu-img %{buildroot}/%{_bindir}/qemu-img-xen +# ln -s qemu-img %{buildroot}/%{_bindir}/qemu-nbd-xen +# END QUBES SPECIFIC PART +for file in bios.bin openbios-sparc32 openbios-sparc64 ppc_rom.bin \ + pxe-e1000.bin pxe-ne2k_pci.bin pxe-pcnet.bin pxe-rtl8139.bin \ + vgabios.bin vgabios-cirrus.bin video.x openbios-ppc bamboo.dtb +do + rm -f %{buildroot}/%{_datadir}/xen/qemu/$file +done + +# README's not intended for end users +rm -f %{buildroot}/%{_sysconfdir}/xen/README* + +# standard gnu info files +rm -rf %{buildroot}/usr/info + +# adhere to Static Library Packaging Guidelines +rm -rf %{buildroot}/%{_libdir}/*.a + +%if %build_efi +# clean up extra efi files +%ifarch %{ix86} +rm -f %{buildroot}/usr/lib64/efi/xen-%{hv_abi}.efi +rm -f %{buildroot}/usr/lib64/efi/xen-4.efi +rm -f %{buildroot}/usr/lib64/efi/xen.efi +# cp -p %{buildroot}/usr/lib64/efi/xen-%{version}{,.notstripped}.efi +# strip -s %{buildroot}/usr/lib64/efi/xen-%{version}.efi +%else +rm -f %{buildroot}/%{_libdir}/efi/xen-%{hv_abi}.efi +rm -f %{buildroot}/%{_libdir}/efi/xen-4.efi +rm -f %{buildroot}/%{_libdir}/efi/xen.efi +# cp -p %{buildroot}/%{_libdir}/efi/xen-%{version}{,.notstripped}.efi +# strip -s %{buildroot}/%{_libdir}/efi/xen-%{version}.efi +%endif +%endif + +%if ! %build_ocaml +rm -rf %{buildroot}/%{_unitdir}/oxenstored.service +%endif + +%if %build_ovmf +cat /usr/share/OVMF/OVMF_{VARS,CODE}.fd >%{buildroot}%{_libexecdir}/%{name}/boot/ovmf.bin +%endif + +############ fixup files in /etc ############ + +# logrotate +mkdir -p %{buildroot}%{_sysconfdir}/logrotate.d/ +install -m 644 %{SOURCE2} %{buildroot}%{_sysconfdir}/logrotate.d/%{name} + +# init scripts +%define initdloc %(test -d /etc/rc.d/init.d/ && echo rc.d/init.d || echo init.d ) + +rm %{buildroot}%{_sysconfdir}/%{initdloc}/xen-watchdog +rm %{buildroot}%{_sysconfdir}/%{initdloc}/xencommons +rm %{buildroot}%{_sysconfdir}/%{initdloc}/xendomains +rm %{buildroot}%{_sysconfdir}/%{initdloc}/xendriverdomain + +# BEGIN QUBES SPECIFIC PART +rm %{buildroot}%{_sysconfdir}/sysconfig/xendomains +mkdir -p %{buildroot}/usr/lib/modules-load.d +cp %{SOURCE3} %{buildroot}/usr/lib/modules-load.d/xen.conf + +# get rid of standard domain starting scripts +rm %{buildroot}%{_unitdir}/xen-qemu-dom0-disk-backend.service +rm %{buildroot}%{_unitdir}/xendomains.service +# END QUBES SPECIFIC PART + +############ create dirs in /var ############ + +mkdir -p %{buildroot}%{_localstatedir}/lib/xen/images +mkdir -p %{buildroot}%{_localstatedir}/log/xen/console + +############ create symlink for x86_64 for compatibility with 4.4 ############ + +%if "%{_libdir}" != "/usr/lib" +ln -s %{_libexecdir}/%{name} %{buildroot}/%{_libdir}/%{name} +%endif + +# BEGIN QUBES SPECIFIC PART +# don't create symlink to qemu-system-i386 +ln -s ../sbin/xl %{buildroot}/%{_bindir}/xl +# END QUBES SPECIFIC PART + +############ debug packaging: list files ############ + +find %{buildroot} -print | xargs ls -ld | sed -e 's|.*%{buildroot}||' > f2.list +diff -u f1.list f2.list || true + +############ assemble license files ############ + +mkdir licensedir +# avoid licensedir to avoid recursion, also stubdom/ioemu and dist +# which are copies of files elsewhere +find . -path licensedir -prune -o -path stubdom/ioemu -prune -o \ + -path dist -prune -o -name COPYING -o -name LICENSE | while read file; do + mkdir -p licensedir/`dirname $file` + install -m 644 $file licensedir/$file +done + +############ all done now ############ + +# BEGIN QUBES SPECIFIC PART +%dnl %post +%dnl %if %with_systemd_presets +%dnl %systemd_post xendomains.service +%dnl %else +%dnl if [ $1 == 1 ]; then +%dnl /bin/systemctl enable xendomains.service +%dnl fi +%dnl %endif + +%dnl %preun +%dnl %if %with_systemd_presets +%dnl %systemd_preun xendomains.service +%dnl %else +%dnl if [ $1 == 0 ]; then +%dnl /bin/systemctl disable xendomains.service +%dnl fi +%dnl %endif +# END QUBES SPECIFIC PART + +%post runtime +%if %with_systemd_presets +# BEGIN QUBES SPECIFIC PART +%systemd_post xenstored.service xenconsoled.service xen-init-dom0.service +# END QUBES SPECIFIC PART +%else +if [ $1 == 1 ]; then + /bin/systemctl enable xenstored.service + /bin/systemctl enable xenconsoled.service +# BEGIN QUBES SPECIFIC PART + /bin/systemctl enable xen-init-dom0.service +# END QUBES SPECIFIC PART +fi +%endif + +%preun runtime +%if %with_systemd_presets +# BEGIN QUBES SPECIFIC PART +%systemd_preun xenstored.service xenconsoled.service xen-init-dom0.service +# END QUBES SPECIFIC PART +%else +if [ $1 == 0 ]; then + /bin/systemctl disable xenstored.service + /bin/systemctl disable xenconsoled.service +# BEGIN QUBES SPECIFIC PART + /bin/systemctl disable xen-init-dom0.service +# END QUBES SPECIFIC PART +fi +%endif + +%posttrans runtime +if [ ! -L /usr/lib/xen -a -d /usr/lib/xen -a -z "$(ls -A /usr/lib/xen)" ]; then + rmdir /usr/lib/xen +fi +if [ ! -e /usr/lib/xen ]; then + ln -s /usr/libexec/xen /usr/lib/xen +fi + +# QUBES SPECIFIC PART: next 2 lines (do not put comment before next section) +%post libs -p /sbin/ldconfig +%postun libs -p /sbin/ldconfig + +%if %build_hyp +%post hypervisor +%if %build_efi +XEN_EFI_VERSION=$(echo %{upstream_version} | sed -e 's/rc./rc/') +EFI_DIR=$(efibootmgr -v 2>/dev/null | awk ' + /^BootCurrent:/ { current=$2; } + /^Boot....\* / { + if ("Boot" current "*" == $1) { + sub(".*File\\(", ""); + sub("\\\\xen.efi\\).*", ""); + gsub("\\\\", "/"); + print; + } + }') +# FAT (on ESP) does not support symlinks +# override the file on purpose +if [ -n "${EFI_DIR}" -a -d "/boot/efi${EFI_DIR}" ]; then + cp -pf /boot/efi/EFI/qubes/xen-$XEN_EFI_VERSION.efi /boot/efi${EFI_DIR}/xen.efi +else + cp -pf /boot/efi/EFI/qubes/xen-$XEN_EFI_VERSION.efi /boot/efi/EFI/qubes/xen.efi +fi +%endif + +if [ -f /boot/efi/EFI/qubes/xen.cfg ]; then + if ! grep -q smt=off /boot/efi/EFI/qubes/xen.cfg; then + sed -i -e 's:^options=.*:\0 smt=off:' /boot/efi/EFI/qubes/xen.cfg + fi + if ! grep -q gnttab_max_frames /boot/efi/EFI/qubes/xen.cfg; then + sed -i -e 's:^options=.*:\0 gnttab_max_frames=2048 gnttab_max_maptrack_frames=4096:' /boot/efi/EFI/qubes/xen.cfg + fi +fi + +if [ -f /etc/default/grub ]; then + if ! grep -q smt=off /etc/default/grub; then + echo 'GRUB_CMDLINE_XEN_DEFAULT="$GRUB_CMDLINE_XEN_DEFAULT smt=off"' >> /etc/default/grub + grub2-mkconfig -o /boot/grub2/grub.cfg + fi + if ! grep -q gnttab_max_frames /etc/default/grub; then + echo 'GRUB_CMDLINE_XEN_DEFAULT="$GRUB_CMDLINE_XEN_DEFAULT gnttab_max_frames=2048 gnttab_max_maptrack_frames=4096"' >> /etc/default/grub + grub2-mkconfig -o /boot/grub2/grub.cfg + fi +fi + +if [ $1 == 1 -a -f /sbin/grub2-mkconfig ]; then + if [ -f /boot/grub2/grub.cfg ]; then + /sbin/grub2-mkconfig -o /boot/grub2/grub.cfg + fi + if [ -f /boot/efi/EFI/qubes/grub.cfg ] && \ + ! grep -q "configfile" /boot/efi/EFI/qubes/grub.cfg; then + /sbin/grub2-mkconfig -o /boot/efi/EFI/qubes/grub.cfg + fi +fi + +%postun hypervisor +if [ -f /sbin/grub2-mkconfig ]; then + if [ -f /boot/grub2/grub.cfg ]; then + /sbin/grub2-mkconfig -o /boot/grub2/grub.cfg + fi + if [ -f /boot/efi/EFI/qubes/grub.cfg ] && \ + ! grep -q "configfile" /boot/efi/EFI/qubes/grub.cfg; then + /sbin/grub2-mkconfig -o /boot/efi/EFI/qubes/grub.cfg + fi +fi +%endif + +%if %build_ocaml +%post ocaml +%if %with_systemd_presets +%systemd_post oxenstored.service +%else +if [ $1 == 1 ]; then + /bin/systemctl enable oxenstored.service +fi +%endif + +%preun ocaml +%if %with_systemd_presets +%systemd_preun oxenstored.service +%else +if [ $1 == 0 ]; then + /bin/systemctl disable oxenstored.service +fi +%endif +%endif + +# Base package only contains XenD/xm python stuff +#files -f xen-xm.lang +%files +%doc COPYING README + +# BEGIN QUBES SPECIFIC PART +%files -n python%{python3_pkgversion}-%{name} +%{python3_sitearch}/%{name} +%{python3_sitearch}/xen-*.egg-info +# END QUBES SPECIFIC PART + +%files libs +%{_libdir}/libxencall.so.1 +%{_libdir}/libxencall.so.1.3 +%{_libdir}/libxenctrl.so.4.* +%{_libdir}/libxendevicemodel.so.1 +%{_libdir}/libxendevicemodel.so.1.4 +%{_libdir}/libxenevtchn.so.1 +%{_libdir}/libxenevtchn.so.1.2 +%{_libdir}/libxenforeignmemory.so.1 +%{_libdir}/libxenforeignmemory.so.1.4 +%{_libdir}/libxengnttab.so.1 +%{_libdir}/libxengnttab.so.1.2 +%{_libdir}/libxenguest.so.4.* +%{_libdir}/libxenlight.so.4.* +%{_libdir}/libxenstat.so.4.* +%{_libdir}/libxenstore.so.4 +%{_libdir}/libxenstore.so.4.0 +%{_libdir}/libxentoolcore.so.1 +%{_libdir}/libxentoolcore.so.1.0 +%{_libdir}/libxentoollog.so.1 +%{_libdir}/libxentoollog.so.1.0 +%{_libdir}/libxenvchan.so.4.* +%{_libdir}/libxlutil.so.4.* +%{_libdir}/libxenhypfs.so.1 +%{_libdir}/libxenhypfs.so.1.0 + +# All runtime stuff except for XenD/xm python stuff +%files runtime +# Hotplug rules + +%dir %attr(0700,root,root) %{_sysconfdir}/%{name} +%dir %attr(0700,root,root) %{_sysconfdir}/%{name}/scripts/ +%config %attr(0700,root,root) %{_sysconfdir}/%{name}/scripts/* + +%{_sysconfdir}/bash_completion.d/xl + +%{_unitdir}/proc-xen.mount +%{_unitdir}/xenstored.service +%{_unitdir}/xenconsoled.service +%{_unitdir}/xen-watchdog.service +# BEGIN QUBES SPECIFIC PART +%{_unitdir}/xen-init-dom0.service +%exclude %{_unitdir}/xendriverdomain.service +# END QUBES SPECIFIC PART +/usr/lib/modules-load.d/xen.conf + +%config(noreplace) %{_sysconfdir}/sysconfig/xencommons +%config(noreplace) %{_sysconfdir}/xen/xl.conf +%config(noreplace) %{_sysconfdir}/xen/cpupool +%config(noreplace) %{_sysconfdir}/xen/xlexample* + +# Rotate console log files +%config(noreplace) %{_sysconfdir}/logrotate.d/xen + +# Programs run by other programs +%dir %{_libexecdir}/%{name} +%dir %{_libexecdir}/%{name}/bin +%attr(0700,root,root) %{_libexecdir}/%{name}/bin/* +# QEMU runtime files +%if %build_qemutrad +%ifnarch armv7hl aarch64 +%dir %{_datadir}/%{name}/qemu +%dir %{_datadir}/%{name}/qemu/keymaps +%{_datadir}/%{name}/qemu/keymaps/* +%endif +%endif + +# man pages +%if %build_docs +%{_mandir}/man1/xentop.1* +%{_mandir}/man8/xentrace.8* +%{_mandir}/man1/xl.1* +%{_mandir}/man5/xl.cfg.5* +%{_mandir}/man5/xl.conf.5* +%{_mandir}/man5/xlcpupool.cfg.5* +%{_mandir}/man1/xenstore* +%{_mandir}/man5/xl-disk-configuration.5.gz +%{_mandir}/man7/xen-pci-device-reservations.7.gz +%{_mandir}/man7/xen-tscmode.7.gz +%{_mandir}/man7/xen-vtpm.7.gz +%{_mandir}/man7/xen-vtpmmgr.7.gz +%{_mandir}/man5/xl-network-configuration.5.gz +%{_mandir}/man7/xen-pv-channel.7.gz +%{_mandir}/man7/xl-numa-placement.7.gz +%{_mandir}/man1/xenhypfs.1.gz +%{_mandir}/man7/xen-vbd-interface.7.gz +%{_mandir}/man5/xl-pci-configuration.5.gz +%endif + +# The firmware +%ifarch %{ix86} x86_64 +%dir %{_libexecdir}/%{name}/boot +%{_libexecdir}/xen/boot/hvmloader +%ifnarch %{ix86} +%{_libexecdir}/%{name}/boot/xen-shim +/usr/lib/debug%{_libexecdir}/xen/boot/xen-shim-syms +%endif +%if %build_ovmf +%{_libexecdir}/xen/boot/ovmf.bin +%endif +%if %build_stubdom +%if %build_qemutrad +%{_libexecdir}/xen/boot/ioemu-stubdom.gz +%endif +%{_libexecdir}/xen/boot/xenstore-stubdom.gz +%{_libexecdir}/xen/boot/xenstorepvh-stubdom.gz +%endif +%endif +%if "%{_libdir}" != "/usr/lib" +%{_libdir}/%{name} +%endif +%ghost /usr/lib/%{name} +# General Xen state +%dir %{_localstatedir}/lib/%{name} +%dir %{_localstatedir}/lib/%{name}/dump +%dir %{_localstatedir}/lib/%{name}/images +# Xenstore runtime state +%ghost %{_localstatedir}/run/xenstored + +# All xenstore CLI tools +%{_bindir}/xenstore +%{_bindir}/xenstore-* +%dnl %{_bindir}/remus +# Misc stuff +%ifnarch armv7hl aarch64 +%{_bindir}/xen-detect +%endif +%{_bindir}/xencov_split +%ifnarch armv7hl aarch64 +%{_sbindir}/gdbsx +%{_sbindir}/xen-kdd +%endif +%ifnarch armv7hl aarch64 +%{_sbindir}/xen-hptool +%{_sbindir}/xen-hvmcrash +%{_sbindir}/xen-hvmctx +%endif +%{_sbindir}/xenconsoled +%{_sbindir}/xenlockprof +%{_sbindir}/xenmon +%{_sbindir}/xentop +%{_sbindir}/xentrace_setmask +%{_sbindir}/xenbaked +%{_sbindir}/xenstored +%{_sbindir}/xenpm +%{_sbindir}/xenpmd +%{_sbindir}/xenperf +%{_sbindir}/xenwatchdogd +%{_sbindir}/xl +%ifnarch armv7hl aarch64 +%{_sbindir}/xen-lowmemd +%endif +%{_sbindir}/xencov +%ifnarch armv7hl aarch64 +%{_sbindir}/xen-mfndump +%endif +%{_bindir}/xenalyze +%{_sbindir}/xentrace +%{_sbindir}/xentrace_setsize +%ifnarch armv7hl aarch64 +%{_bindir}/xen-cpuid +%endif +%{_sbindir}/xen-livepatch +%{_sbindir}/xen-diag +%ifnarch armv7hl aarch64 +%{_sbindir}/xen-ucode +%{_sbindir}/xen-memshare +%{_sbindir}/xen-mceinj +%{_sbindir}/xen-vmtrace +%endif +%{_bindir}/vchan-socket-proxy +%{_sbindir}/xenhypfs +%{_sbindir}/xen-access + +# BEGIN QUBES SPECIFIC PART +%{_bindir}/xl +# END QUBES SPECIFIC PART + +# Xen logfiles +%dir %attr(0700,root,root) %{_localstatedir}/log/xen +# Guest/HV console logs +%dir %attr(0700,root,root) %{_localstatedir}/log/xen/console + +%files hypervisor +%if %build_hyp +%defattr(-,root,root) +%ifnarch armv7hl aarch64 +/boot/xen-*.gz +# BEGIN QUBES SPECIFIC PART +# /boot/xen.gz +# END QUBES SPECIFIC PART +/boot/xen*.config +%else +/boot/xen* +%endif +%if %build_xsm +%dir %attr(0755,root,root) /boot/flask +/boot/flask/xenpolicy* +%endif +%if %build_efi +/boot/efi/EFI/qubes/*.efi +%endif +/usr/lib/debug/xen* +%endif + +%if %build_docs +%files doc +%doc docs/misc/ +%doc dist/install/usr/share/doc/xen/html +%endif + +%files devel +%{_includedir}/*.h +%dir %{_includedir}/xen +%{_includedir}/xen/* +%dir %{_includedir}/xenstore-compat +%{_includedir}/xenstore-compat/* +%{_libdir}/*.so +%{_libdir}/pkgconfig/* + +%files licenses +%doc licensedir/* + +%if %build_ocaml +%files ocaml +%{_libdir}/ocaml/xen* +%exclude %{_libdir}/ocaml/xen*/*.a +%exclude %{_libdir}/ocaml/xen*/*.cmxa +%exclude %{_libdir}/ocaml/xen*/*.cmx +%{_libdir}/ocaml/stublibs/*.so +%{_libdir}/ocaml/stublibs/*.so.owner +%{_sbindir}/oxenstored +%config(noreplace) %{_sysconfdir}/xen/oxenstored.conf +%{_unitdir}/oxenstored.service + +%files ocaml-devel +%{_libdir}/ocaml/xen*/*.a +%{_libdir}/ocaml/xen*/*.cmxa +%{_libdir}/ocaml/xen*/*.cmx +%endif + +%changelog +@CHANGELOG@ + From 4e020c94bf8493378d38506f479202ea9a460e80 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Sun, 30 Jul 2023 00:19:23 +0300 Subject: [PATCH 18/46] .github/workflows/build.yml: build QubesOS package Signed-off-by: Krystian Hebel --- .github/workflows/build.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000..4bfc5ddd8a --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,15 @@ +name: Test build and package QubesOS RPMs + +on: + push: + branches: + - 'aem*' + tags: + - '*' + +jobs: + qubes-dom0-package: + uses: TrenchBoot/.github/.github/workflows/qubes-dom0-packagev2.yml@master + with: + qubes-component: 'vmm-xen' + qubes-pkg-src-dir: '.' From be844090a8c36f30bbfce6c9d01b7bd0a1a12646 Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Mon, 17 Apr 2023 20:10:13 +0200 Subject: [PATCH 19/46] x86/include/asm/intel_txt.h: constants and accessors for TXT registers and heap The file contains TXT register spaces base address, registers offsets, error codes and inline functions for accessing structures stored on TXT heap. Signed-off-by: Krystian Hebel Signed-off-by: Sergii Dmytruk --- xen/arch/x86/include/asm/intel_txt.h | 268 +++++++++++++++++++++++++++ xen/arch/x86/tboot.c | 20 +- 2 files changed, 270 insertions(+), 18 deletions(-) create mode 100644 xen/arch/x86/include/asm/intel_txt.h diff --git a/xen/arch/x86/include/asm/intel_txt.h b/xen/arch/x86/include/asm/intel_txt.h new file mode 100644 index 0000000000..f3d1b8a0c8 --- /dev/null +++ b/xen/arch/x86/include/asm/intel_txt.h @@ -0,0 +1,268 @@ +/* + * TXT configuration registers (offsets from TXT_{PUB, PRIV}_CONFIG_REGS_BASE) + */ +#define TXT_PUB_CONFIG_REGS_BASE 0xfed30000 +#define TXT_PRIV_CONFIG_REGS_BASE 0xfed20000 + +/* The same set of registers is exposed twice (with different permissions) and + * they are allocated continuously with page alignment. */ +#define NR_TXT_CONFIG_SIZE \ + (TXT_PUB_CONFIG_REGS_BASE - TXT_PRIV_CONFIG_REGS_BASE) + +/* Offsets from pub/priv config space. */ +#define TXTCR_STS 0x0000 +#define TXTCR_ESTS 0x0008 +#define TXTCR_ERRORCODE 0x0030 +#define TXTCR_CMD_RESET 0x0038 +#define TXTCR_CMD_CLOSE_PRIVATE 0x0048 +#define TXTCR_DIDVID 0x0110 +#define TXTCR_VER_EMIF 0x0200 +#define TXTCR_CMD_UNLOCK_MEM_CONFIG 0x0218 +#define TXTCR_SINIT_BASE 0x0270 +#define TXTCR_SINIT_SIZE 0x0278 +#define TXTCR_MLE_JOIN 0x0290 +#define TXTCR_HEAP_BASE 0x0300 +#define TXTCR_HEAP_SIZE 0x0308 +#define TXTCR_SCRATCHPAD 0x0378 +#define TXTCR_CMD_OPEN_LOCALITY1 0x0380 +#define TXTCR_CMD_CLOSE_LOCALITY1 0x0388 +#define TXTCR_CMD_OPEN_LOCALITY2 0x0390 +#define TXTCR_CMD_CLOSE_LOCALITY2 0x0398 +#define TXTCR_CMD_SECRETS 0x08e0 +#define TXTCR_CMD_NO_SECRETS 0x08e8 +#define TXTCR_E2STS 0x08f0 + +/* + * Secure Launch Defined Error Codes used in MLE-initiated TXT resets. + * + * TXT Specification + * Appendix I ACM Error Codes + */ +#define SLAUNCH_ERROR_GENERIC 0xc0008001 +#define SLAUNCH_ERROR_TPM_INIT 0xc0008002 +#define SLAUNCH_ERROR_TPM_INVALID_LOG20 0xc0008003 +#define SLAUNCH_ERROR_TPM_LOGGING_FAILED 0xc0008004 +#define SLAUNCH_ERROR_REGION_STRADDLE_4GB 0xc0008005 +#define SLAUNCH_ERROR_TPM_EXTEND 0xc0008006 +#define SLAUNCH_ERROR_MTRR_INV_VCNT 0xc0008007 +#define SLAUNCH_ERROR_MTRR_INV_DEF_TYPE 0xc0008008 +#define SLAUNCH_ERROR_MTRR_INV_BASE 0xc0008009 +#define SLAUNCH_ERROR_MTRR_INV_MASK 0xc000800a +#define SLAUNCH_ERROR_MSR_INV_MISC_EN 0xc000800b +#define SLAUNCH_ERROR_INV_AP_INTERRUPT 0xc000800c +#define SLAUNCH_ERROR_INTEGER_OVERFLOW 0xc000800d +#define SLAUNCH_ERROR_HEAP_WALK 0xc000800e +#define SLAUNCH_ERROR_HEAP_MAP 0xc000800f +#define SLAUNCH_ERROR_REGION_ABOVE_4GB 0xc0008010 +#define SLAUNCH_ERROR_HEAP_INVALID_DMAR 0xc0008011 +#define SLAUNCH_ERROR_HEAP_DMAR_SIZE 0xc0008012 +#define SLAUNCH_ERROR_HEAP_DMAR_MAP 0xc0008013 +#define SLAUNCH_ERROR_HI_PMR_BASE 0xc0008014 +#define SLAUNCH_ERROR_HI_PMR_SIZE 0xc0008015 +#define SLAUNCH_ERROR_LO_PMR_BASE 0xc0008016 +#define SLAUNCH_ERROR_LO_PMR_SIZE 0xc0008017 +#define SLAUNCH_ERROR_LO_PMR_MLE 0xc0008018 +#define SLAUNCH_ERROR_INITRD_TOO_BIG 0xc0008019 +#define SLAUNCH_ERROR_HEAP_ZERO_OFFSET 0xc000801a +#define SLAUNCH_ERROR_WAKE_BLOCK_TOO_SMALL 0xc000801b +#define SLAUNCH_ERROR_MLE_BUFFER_OVERLAP 0xc000801c +#define SLAUNCH_ERROR_BUFFER_BEYOND_PMR 0xc000801d +#define SLAUNCH_ERROR_OS_SINIT_BAD_VERSION 0xc000801e +#define SLAUNCH_ERROR_EVENTLOG_MAP 0xc000801f +#define SLAUNCH_ERROR_TPM_NUMBER_ALGS 0xc0008020 +#define SLAUNCH_ERROR_TPM_UNKNOWN_DIGEST 0xc0008021 +#define SLAUNCH_ERROR_TPM_INVALID_EVENT 0xc0008022 + +#define SLAUNCH_BOOTLOADER_MAGIC 0x4c534254 + +#ifndef __ASSEMBLY__ + +/* We need to differentiate between pre- and post paging enabled. */ +#ifdef __XEN_CONFIG_H__ +#include +#define _txt(x) _p(x) +#else +#include +#include // __va() +#define _txt(x) __va(x) +#endif + +/* + * Always use private space as some of registers are either read-only or not + * present in public space. + */ +static inline uint64_t read_txt_reg(int reg_no) +{ + volatile uint64_t *reg = _txt(TXT_PRIV_CONFIG_REGS_BASE + reg_no); + return *reg; +} + +static inline void write_txt_reg(int reg_no, uint64_t val) +{ + volatile uint64_t *reg = _txt(TXT_PRIV_CONFIG_REGS_BASE + reg_no); + *reg = val; + /* This serves as TXT register barrier */ + (void)read_txt_reg(TXTCR_ESTS); +} + +static inline void txt_reset(uint32_t error) +{ + write_txt_reg(TXTCR_ERRORCODE, error); + write_txt_reg(TXTCR_CMD_NO_SECRETS, 1); + write_txt_reg(TXTCR_CMD_UNLOCK_MEM_CONFIG, 1); + write_txt_reg(TXTCR_CMD_RESET, 1); + while (1); +} + +/* + * Secure Launch defined OS/MLE TXT Heap table + */ +struct txt_os_mle_data { + uint32_t version; + uint32_t boot_params_addr; + uint32_t slrt; + uint32_t txt_info; + uint32_t ap_wake_block; + uint32_t ap_wake_block_size; + uint8_t mle_scratch[64]; +} __packed; + +/* + * TXT specification defined BIOS data TXT Heap table + */ +struct txt_bios_data { + uint32_t version; /* Currently 5 for TPM 1.2 and 6 for TPM 2.0 */ + uint32_t bios_sinit_size; + uint64_t reserved1; + uint64_t reserved2; + uint32_t num_logical_procs; + /* Versions >= 3 && < 5 */ + uint32_t sinit_flags; + /* Versions >= 5 with updates in version 6 */ + uint32_t mle_flags; + /* Versions >= 4 */ + /* Ext Data Elements */ +} __packed; + +/* + * TXT specification defined OS/SINIT TXT Heap table + */ +struct txt_os_sinit_data { + uint32_t version; /* Currently 6 for TPM 1.2 and 7 for TPM 2.0 */ + uint32_t flags; /* Reserved in version 6 */ + uint64_t mle_ptab; + uint64_t mle_size; + uint64_t mle_hdr_base; + uint64_t vtd_pmr_lo_base; + uint64_t vtd_pmr_lo_size; + uint64_t vtd_pmr_hi_base; + uint64_t vtd_pmr_hi_size; + uint64_t lcp_po_base; + uint64_t lcp_po_size; + uint32_t capabilities; + /* Version = 5 */ + uint64_t efi_rsdt_ptr; /* RSD*P* in versions >= 6 */ + /* Versions >= 6 */ + /* Ext Data Elements */ +} __packed; + +/* + * TXT specification defined SINIT/MLE TXT Heap table + */ +struct txt_sinit_mle_data { + uint32_t version; /* Current values are 6 through 9 */ + /* Versions <= 8, fields until lcp_policy_control must be 0 for >= 9 */ + uint8_t bios_acm_id[20]; + uint32_t edx_senter_flags; + uint64_t mseg_valid; + uint8_t sinit_hash[20]; + uint8_t mle_hash[20]; + uint8_t stm_hash[20]; + uint8_t lcp_policy_hash[20]; + uint32_t lcp_policy_control; + /* Versions >= 7 */ + uint32_t rlp_wakeup_addr; + uint32_t reserved; + uint32_t num_of_sinit_mdrs; + uint32_t sinit_mdrs_table_offset; + uint32_t sinit_vtd_dmar_table_size; + uint32_t sinit_vtd_dmar_table_offset; + /* Versions >= 8 */ + uint32_t processor_scrtm_status; + /* Versions >= 9 */ + /* Ext Data Elements */ +} __packed; + +/* + * Functions to extract data from the Intel TXT Heap Memory. The layout + * of the heap is as follows: + * +------------------------------------+ + * | Size of Bios Data table (uint64_t) | + * +------------------------------------+ + * | Bios Data table | + * +------------------------------------+ + * | Size of OS MLE table (uint64_t) | + * +------------------------------------+ + * | OS MLE table | + * +-------------------------------- + + * | Size of OS SINIT table (uint64_t) | + * +------------------------------------+ + * | OS SINIT table | + * +------------------------------------+ + * | Size of SINIT MLE table (uint64_t) | + * +------------------------------------+ + * | SINIT MLE table | + * +------------------------------------+ + * + * NOTE: the table size fields include the 8 byte size field itself. + */ +static inline uint64_t txt_bios_data_size(void *heap) +{ + return *((uint64_t *)heap) - sizeof(uint64_t); +} + +static inline void *txt_bios_data_start(void *heap) +{ + return heap + sizeof(uint64_t); +} + +static inline uint64_t txt_os_mle_data_size(void *heap) +{ + return *((uint64_t *)(txt_bios_data_start(heap) + + txt_bios_data_size(heap))) - + sizeof(uint64_t); +} + +static inline void *txt_os_mle_data_start(void *heap) +{ + return txt_bios_data_start(heap) + txt_bios_data_size(heap) + + sizeof(uint64_t); +} + +static inline uint64_t txt_os_sinit_data_size(void *heap) +{ + return *((uint64_t *)(txt_os_mle_data_start(heap) + + txt_os_mle_data_size(heap))) - + sizeof(uint64_t); +} + +static inline void *txt_os_sinit_data_start(void *heap) +{ + return txt_os_mle_data_start(heap) + txt_os_mle_data_size(heap) + + sizeof(uint64_t); +} + +static inline uint64_t txt_sinit_mle_data_size(void *heap) +{ + return *((uint64_t *)(txt_os_sinit_data_start(heap) + + txt_os_sinit_data_size(heap))) - + sizeof(uint64_t); +} + +static inline void *txt_sinit_mle_data_start(void *heap) +{ + return txt_os_sinit_data_start(heap) + txt_os_sinit_data_size(heap) + + sizeof(uint64_t); +} + +#endif /* __ASSEMBLY__ */ diff --git a/xen/arch/x86/tboot.c b/xen/arch/x86/tboot.c index d5db60d335..f68354c374 100644 --- a/xen/arch/x86/tboot.c +++ b/xen/arch/x86/tboot.c @@ -15,6 +15,7 @@ #include #include #include +#include #include @@ -35,23 +36,6 @@ static uint64_t __initdata sinit_base, __initdata sinit_size; static bool __ro_after_init is_vtd; -/* - * TXT configuration registers (offsets from TXT_{PUB, PRIV}_CONFIG_REGS_BASE) - */ - -#define TXT_PUB_CONFIG_REGS_BASE 0xfed30000 -#define TXT_PRIV_CONFIG_REGS_BASE 0xfed20000 - -/* # pages for each config regs space - used by fixmap */ -#define NR_TXT_CONFIG_PAGES ((TXT_PUB_CONFIG_REGS_BASE - \ - TXT_PRIV_CONFIG_REGS_BASE) >> PAGE_SHIFT) - -/* offsets from pub/priv config space */ -#define TXTCR_SINIT_BASE 0x0270 -#define TXTCR_SINIT_SIZE 0x0278 -#define TXTCR_HEAP_BASE 0x0300 -#define TXTCR_HEAP_SIZE 0x0308 - #define SHA1_SIZE 20 typedef uint8_t sha1_hash_t[SHA1_SIZE]; @@ -409,7 +393,7 @@ int __init tboot_protect_mem_regions(void) /* TXT Private Space */ rc = e820_change_range_type(&e820, TXT_PRIV_CONFIG_REGS_BASE, - TXT_PRIV_CONFIG_REGS_BASE + NR_TXT_CONFIG_PAGES * PAGE_SIZE, + TXT_PRIV_CONFIG_REGS_BASE + NR_TXT_CONFIG_SIZE, E820_RESERVED, E820_UNUSABLE); if ( !rc ) return 0; From a17a97fe0814cd882f998d8176bd24bd27cd83d8 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Sun, 29 Oct 2023 00:29:30 +0300 Subject: [PATCH 20/46] include/xen/slr_table.h: Secure Launch Resource Table definitions The file provides constants, structures and several helper functions for parsing SLRT. slr_add_entry() and slr_init_table() were omitted to not have issues with memcpy() usage (it comes from different places for different translation units). Signed-off-by: Sergii Dmytruk --- xen/include/xen/slr_table.h | 263 ++++++++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 xen/include/xen/slr_table.h diff --git a/xen/include/xen/slr_table.h b/xen/include/xen/slr_table.h new file mode 100644 index 0000000000..46c890c24a --- /dev/null +++ b/xen/include/xen/slr_table.h @@ -0,0 +1,263 @@ +/* SPDX-License-Identifier: GPL-3.0 */ + +/* + * Copyright (C) 2023 Oracle and/or its affiliates. + * + * Secure Launch Resource Table definitions + */ + +#ifndef _SLR_TABLE_H +#define _SLR_TABLE_H + +#define UEFI_SLR_TABLE_GUID \ + { 0x877a9b2a, 0x0385, 0x45d1, { 0xa0, 0x34, 0x9d, 0xac, 0x9c, 0x9e, 0x56, 0x5f }} + +/* SLR table header values */ +#define SLR_TABLE_MAGIC 0x4452544d +#define SLR_TABLE_REVISION 1 + +/* Current revisions for the policy and UEFI config */ +#define SLR_POLICY_REVISION 1 +#define SLR_UEFI_CONFIG_REVISION 1 + +/* SLR defined architectures */ +#define SLR_INTEL_TXT 1 +#define SLR_AMD_SKINIT 2 + +/* SLR defined bootloaders */ +#define SLR_BOOTLOADER_INVALID 0 +#define SLR_BOOTLOADER_GRUB 1 + +/* Log formats */ +#define SLR_DRTM_TPM12_LOG 1 +#define SLR_DRTM_TPM20_LOG 2 + +/* DRTM Policy Entry Flags */ +#define SLR_POLICY_FLAG_MEASURED 0x1 +#define SLR_POLICY_IMPLICIT_SIZE 0x2 + +/* Array Lengths */ +#define TPM_EVENT_INFO_LENGTH 32 +#define TXT_VARIABLE_MTRRS_LENGTH 32 + +/* Tags */ +#define SLR_ENTRY_INVALID 0x0000 +#define SLR_ENTRY_DL_INFO 0x0001 +#define SLR_ENTRY_LOG_INFO 0x0002 +#define SLR_ENTRY_DRTM_POLICY 0x0003 +#define SLR_ENTRY_INTEL_INFO 0x0004 +#define SLR_ENTRY_AMD_INFO 0x0005 +#define SLR_ENTRY_ARM_INFO 0x0006 +#define SLR_ENTRY_UEFI_INFO 0x0007 +#define SLR_ENTRY_UEFI_CONFIG 0x0008 +#define SLR_ENTRY_END 0xffff + +/* Entity Types */ +#define SLR_ET_UNSPECIFIED 0x0000 +#define SLR_ET_SLRT 0x0001 +#define SLR_ET_BOOT_PARAMS 0x0002 +#define SLR_ET_SETUP_DATA 0x0003 +#define SLR_ET_CMDLINE 0x0004 +#define SLR_ET_UEFI_MEMMAP 0x0005 +#define SLR_ET_RAMDISK 0x0006 +#define SLR_ET_MULTIBOOT2_INFO 0x0007 +#define SLR_ET_MULTIBOOT2_MODULE 0x0008 +#define SLR_ET_TXT_OS2MLE 0x0010 +#define SLR_ET_UNUSED 0xffff + +/* + * Primary SLR Table Header + */ +struct slr_table +{ + uint32_t magic; + uint16_t revision; + uint16_t architecture; + uint32_t size; + uint32_t max_size; + /* entries[] */ +} __packed; + +/* + * Common SLRT Table Header + */ +struct slr_entry_hdr +{ + uint32_t tag; + uint32_t size; +} __packed; + +/* + * Boot loader context + */ +struct slr_bl_context +{ + uint16_t bootloader; + uint16_t reserved[3]; + uint64_t context; +} __packed; + +/* + * DRTM Dynamic Launch Configuration + */ +struct slr_entry_dl_info +{ + struct slr_entry_hdr hdr; + uint64_t dce_size; + uint64_t dce_base; + uint64_t dlme_size; + uint64_t dlme_base; + uint64_t dlme_entry; + struct slr_bl_context bl_context; + uint64_t dl_handler; +} __packed; + +/* + * TPM Log Information + */ +struct slr_entry_log_info +{ + struct slr_entry_hdr hdr; + uint16_t format; + uint16_t reserved; + uint32_t size; + uint64_t addr; +} __packed; + +/* + * DRTM Measurement Entry + */ +struct slr_policy_entry +{ + uint16_t pcr; + uint16_t entity_type; + uint16_t flags; + uint16_t reserved; + uint64_t size; + uint64_t entity; + char evt_info[TPM_EVENT_INFO_LENGTH]; +} __packed; + +/* + * DRTM Measurement Policy + */ +struct slr_entry_policy +{ + struct slr_entry_hdr hdr; + uint16_t reserved[2]; + uint16_t revision; + uint16_t nr_entries; + struct slr_policy_entry policy_entries[]; +} __packed; + +/* + * Secure Launch defined MTRR saving structures + */ +struct slr_txt_mtrr_pair +{ + uint64_t mtrr_physbase; + uint64_t mtrr_physmask; +} __packed; + +struct slr_txt_mtrr_state +{ + uint64_t default_mem_type; + uint64_t mtrr_vcnt; + struct slr_txt_mtrr_pair mtrr_pair[TXT_VARIABLE_MTRRS_LENGTH]; +} __packed; + +/* + * Intel TXT Info table + */ +struct slr_entry_intel_info +{ + struct slr_entry_hdr hdr; + uint64_t txt_heap; + uint64_t saved_misc_enable_msr; + struct slr_txt_mtrr_state saved_bsp_mtrrs; +} __packed; + +/* + * AMD SKINIT Info table + */ +struct slr_entry_amd_info +{ + struct slr_entry_hdr hdr; +} __packed; + +/* + * ARM DRTM Info table + */ +struct slr_entry_arm_info +{ + struct slr_entry_hdr hdr; +} __packed; + +/* + * UEFI config measurement entry + */ +struct slr_uefi_cfg_entry +{ + uint16_t pcr; + uint16_t reserved; + uint32_t size; + uint64_t cfg; /* address or value */ + char evt_info[TPM_EVENT_INFO_LENGTH]; +} __packed; + +struct slr_entry_uefi_config +{ + struct slr_entry_hdr hdr; + uint16_t reserved[2]; + uint16_t revision; + uint16_t nr_entries; + struct slr_uefi_cfg_entry uefi_cfg_entries[]; +} __packed; + +static inline void * +slr_end_of_entries(struct slr_table *table) +{ + return (uint8_t *)table + table->size; +} + +static inline struct slr_entry_hdr * +slr_next_entry(struct slr_table *table, struct slr_entry_hdr *curr) +{ + struct slr_entry_hdr *next = (struct slr_entry_hdr *) + ((uint8_t *)curr + curr->size); + + if ( (void *)next >= slr_end_of_entries(table) ) + return NULL; + if ( next->tag == SLR_ENTRY_END ) + return NULL; + + return next; +} + +static inline struct slr_entry_hdr * +slr_next_entry_by_tag (struct slr_table *table, + struct slr_entry_hdr *entry, + uint16_t tag) +{ + if ( !entry ) /* Start from the beginning */ + entry = (struct slr_entry_hdr *)((uint8_t *)table + sizeof(*table)); + + for ( ; ; ) + { + if ( entry->tag == tag ) + return entry; + + entry = slr_next_entry(table, entry); + if ( !entry ) + return NULL; + } + + return NULL; +} + +/* + * slr_add_entry() and slr_init_table() were omitted to not have issues with + * memcpy() usage. + */ + +#endif /* _SLR_TABLE_H */ From c5a3ea087c713b994f2903678f300545b1397231 Mon Sep 17 00:00:00 2001 From: Kacper Stojek Date: Wed, 31 Aug 2022 15:03:51 +0200 Subject: [PATCH 21/46] x86/boot: add MLE header and new entry point MLE header is used with Intel TXT, together with MB2 headers. Entrypoint is different, but it is used just to differentiate from other entries by moving a magic number to EAX. Execution environment is similar to that of Multiboot 2 and code falls through to MB2's entry point. Signed-off-by: Kacper Stojek Signed-off-by: Krystian Hebel Signed-off-by: Sergii Dmytruk --- docs/hypervisor-guide/x86/how-xen-boots.rst | 5 ++ xen/arch/x86/boot/head.S | 53 +++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/docs/hypervisor-guide/x86/how-xen-boots.rst b/docs/hypervisor-guide/x86/how-xen-boots.rst index 8b3229005c..98c196516b 100644 --- a/docs/hypervisor-guide/x86/how-xen-boots.rst +++ b/docs/hypervisor-guide/x86/how-xen-boots.rst @@ -55,6 +55,11 @@ If ``CONFIG_PVH_GUEST`` was selected at build time, an Elf note is included which indicates the ability to use the PVH boot protocol, and registers ``__pvh_start`` as the entrypoint, entered in 32bit mode. +MLE header is used with Intel TXT, together with MB2 headers. Entrypoint is +different, but it is used just to differentiate from other entries by moving +a magic number to EAX. Execution environment is similar to that of Multiboot 2 +and code falls through to ``start``. + xen.gz ~~~~~~ diff --git a/xen/arch/x86/boot/head.S b/xen/arch/x86/boot/head.S index 1b3bd16fe5..d1c9400e90 100644 --- a/xen/arch/x86/boot/head.S +++ b/xen/arch/x86/boot/head.S @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -126,6 +127,25 @@ multiboot2_header: .size multiboot2_header, . - multiboot2_header .type multiboot2_header, @object + .balign 16 +mle_header: + .long 0x9082ac5a /* UUID0 */ + .long 0x74a7476f /* UUID1 */ + .long 0xa2555c0f /* UUID2 */ + .long 0x42b651cb /* UUID3 */ + .long 0x00000034 /* MLE header size */ + .long 0x00020002 /* MLE version 2.2 */ + .long (slaunch_stub_entry - start) /* Linear entry point of MLE (SINIT virt. address) */ + .long 0x00000000 /* First valid page of MLE */ + .long 0x00000000 /* Offset within binary of first byte of MLE */ + .long (_end - start) /* Offset within binary of last byte + 1 of MLE */ + .long 0x00000223 /* Bit vector of MLE-supported capabilities */ + .long 0x00000000 /* Starting linear address of command line (unused) */ + .long 0x00000000 /* Ending linear address of command line (unused) */ + + .size mle_header, .-mle_header + .type mle_header, @object + .section .init.rodata, "a", @progbits .Lbad_cpu_msg: .asciz "ERR: Not a 64-bit CPU!" @@ -331,6 +351,38 @@ cs32_switch: /* Jump to earlier loaded address. */ jmp *%edi + /* + * Entry point for TrenchBoot Secure Launch on Intel TXT platforms. + * + * CPU is in 32b protected mode with paging disabled. On entry: + * - %ebx = %eip = MLE entry point, + * - stack pointer is undefined, + * - CS is flat 4GB code segment, + * - DS, ES, SS, FS and GS are undefined according to TXT SDG, but this + * would make it impossible to initialize GDTR, because GDT base must + * be relocated in the descriptor, which requires write access that + * CS doesn't provide. Instead we have to assume that DS is set by + * SINIT ACM as flat 4GB data segment. + * + * Additional restrictions: + * - some MSRs are partially cleared, among them IA32_MISC_ENABLE, so + * some capabilities might be reported as disabled even if they are + * supported by CPU + * - interrupts (including NMIs and SMIs) are disabled and must be + * enabled later + * - trying to enter real mode results in reset + * - APs must be brought up by MONITOR or GETSEC[WAKEUP], depending on + * which is supported by a given SINIT ACM + */ +slaunch_stub_entry: + /* Calculate the load base address. */ + mov %ebx, %esi + sub $sym_offs(slaunch_stub_entry), %esi + + /* Mark Secure Launch boot protocol and jump to common entry. */ + mov $SLAUNCH_BOOTLOADER_MAGIC, %eax + jmp .Lset_stack + #ifdef CONFIG_PVH_GUEST ELFNOTE(Xen, XEN_ELFNOTE_PHYS32_ENTRY, .long sym_offs(__pvh_start)) @@ -370,6 +422,7 @@ __start: /* Restore the clobbered field. */ mov %edx, (%ebx) +.Lset_stack: /* Set up stack. */ lea STACK_SIZE - CPUINFO_sizeof + sym_esi(cpu0_stack), %esp From c089806b917334a7eda45ce1c0173ada90d2a928 Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Mon, 17 Apr 2023 20:09:54 +0200 Subject: [PATCH 22/46] x86/boot/txt_early: add early TXT tests and restore MBI pointer These tests validate that important parts of memory are protected against DMA attacks, including Xen and MBI. Modules can be tested later, when it is possible to report issues to user before invoking TXT reset. TPM event log validation is temporarily disabled due to issue with its allocation by bootloader (GRUB) which will need to be modified to address this. Ultimately event log will also have to be validated early as it is used immediately after these tests to hold MBI measurements. See larger comment in verify_pmr_ranges(). Signed-off-by: Krystian Hebel Signed-off-by: Sergii Dmytruk --- xen/arch/x86/Makefile | 1 + xen/arch/x86/boot/Makefile | 3 +- xen/arch/x86/boot/head.S | 21 +++++ xen/arch/x86/boot/txt_early.c | 122 +++++++++++++++++++++++++++ xen/arch/x86/include/asm/intel_txt.h | 28 ++++++ xen/arch/x86/intel_txt.c | 11 +++ 6 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 xen/arch/x86/boot/txt_early.c create mode 100644 xen/arch/x86/intel_txt.c diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index b35fd5196c..c0f2c72781 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -57,6 +57,7 @@ obj-y += pci.o obj-y += physdev.o obj-$(CONFIG_COMPAT) += x86_64/physdev.o obj-$(CONFIG_X86_PSR) += psr.o +obj-y += intel_txt.o obj-y += setup.o obj-y += shutdown.o obj-y += smp.o diff --git a/xen/arch/x86/boot/Makefile b/xen/arch/x86/boot/Makefile index 607eb431d0..f5c30ace4d 100644 --- a/xen/arch/x86/boot/Makefile +++ b/xen/arch/x86/boot/Makefile @@ -5,6 +5,7 @@ obj-bin-y += $(obj64) obj32 := cmdline.32.o obj32 += reloc.32.o obj32 += reloc-trampoline.32.o +obj32 += txt_early.32.o obj64 := reloc-trampoline.o @@ -80,7 +81,7 @@ cmd_combine = \ --bin1 $(obj)/built-in-32.base.bin \ --bin2 $(obj)/built-in-32.offset.bin \ --map $(obj)/built-in-32.base.map \ - --exports cmdline_parse_early,reloc,reloc_trampoline32 \ + --exports cmdline_parse_early,reloc,reloc_trampoline32,txt_early_tests \ --output $@ targets += built-in-32.S diff --git a/xen/arch/x86/boot/head.S b/xen/arch/x86/boot/head.S index d1c9400e90..e63226e09c 100644 --- a/xen/arch/x86/boot/head.S +++ b/xen/arch/x86/boot/head.S @@ -471,6 +471,10 @@ __start: /* Bootloaders may set multiboot{1,2}.mem_lower to a nonzero value. */ xor %edx,%edx + /* Check for TrenchBoot slaunch bootloader. */ + cmp $SLAUNCH_BOOTLOADER_MAGIC,%eax + je .Lslaunch_proto + /* Check for Multiboot2 bootloader. */ cmp $MULTIBOOT2_BOOTLOADER_MAGIC,%eax je .Lmultiboot2_proto @@ -486,6 +490,23 @@ __start: cmovnz MB_mem_lower(%ebx),%edx jmp trampoline_bios_setup +.Lslaunch_proto: + /* Save information that TrenchBoot slaunch was used. */ + movb $1, sym_esi(slaunch_active) + + lea sym_offs(__2M_rwdata_end), %ecx /* end of target image */ + lea sym_offs(_start), %edx /* target base address */ + mov %esi, %eax /* load base address */ + /* txt_early_tests(load/eax, tgt/edx, tgt_end/ecx) using fastcall. */ + call txt_early_tests + + /* + * txt_early_tests() returns MBI address, move it to EBX, move magic + * number expected by Multiboot 2 to EAX and fall through. + */ + movl %eax,%ebx + movl $MULTIBOOT2_BOOTLOADER_MAGIC,%eax + .Lmultiboot2_proto: /* Skip Multiboot2 information fixed part. */ lea (MB2_fixed_sizeof+MULTIBOOT2_TAG_ALIGN-1)(%ebx),%ecx diff --git a/xen/arch/x86/boot/txt_early.c b/xen/arch/x86/boot/txt_early.c new file mode 100644 index 0000000000..dcbddf057c --- /dev/null +++ b/xen/arch/x86/boot/txt_early.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2022-2024 3mdeb Sp. z o.o. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include +#include +#include + +static void verify_pmr_ranges(struct txt_os_mle_data *os_mle, + struct txt_os_sinit_data *os_sinit, + uint32_t load_base_addr, uint32_t tgt_base_addr, + uint32_t xen_size) +{ + int check_high_pmr = 0; + + /* Verify the value of the low PMR base. It should always be 0. */ + if ( os_sinit->vtd_pmr_lo_base != 0 ) + txt_reset(SLAUNCH_ERROR_LO_PMR_BASE); + + /* + * Low PMR size should not be 0 on current platforms. There is an ongoing + * transition to TPR-based DMA protection instead of PMR-based; this is not + * yet supported by the code. + */ + if ( os_sinit->vtd_pmr_lo_size == 0 ) + txt_reset(SLAUNCH_ERROR_LO_PMR_SIZE); + + /* Check if regions overlap. Treat regions with no hole between as error. */ + if ( os_sinit->vtd_pmr_hi_size != 0 && + os_sinit->vtd_pmr_hi_base <= os_sinit->vtd_pmr_lo_size ) + txt_reset(SLAUNCH_ERROR_HI_PMR_BASE); + + /* All regions accessed by 32b code must be below 4G. */ + if ( os_sinit->vtd_pmr_hi_base + os_sinit->vtd_pmr_hi_size <= + 0x100000000ull ) + check_high_pmr = 1; + + /* + * ACM checks that TXT heap and MLE memory is protected against DMA. We have + * to check if MBI and whole Xen memory is protected. The latter is done in + * case bootloader failed to set whole image as MLE and to make sure that + * both pre- and post-relocation code is protected. + */ + + /* Check if all of Xen before relocation is covered by PMR. */ + if ( !is_in_pmr(os_sinit, load_base_addr, xen_size, check_high_pmr) ) + txt_reset(SLAUNCH_ERROR_LO_PMR_MLE); + + /* Check if all of Xen after relocation is covered by PMR. */ + if ( load_base_addr != tgt_base_addr && + !is_in_pmr(os_sinit, tgt_base_addr, xen_size, check_high_pmr) ) + txt_reset(SLAUNCH_ERROR_LO_PMR_MLE); + + /* Check if MBI is covered by PMR. MBI starts with 'uint32_t total_size'. */ + if ( !is_in_pmr(os_sinit, os_mle->boot_params_addr, + *(uint32_t *)os_mle->boot_params_addr, check_high_pmr) ) + txt_reset(SLAUNCH_ERROR_BUFFER_BEYOND_PMR); + + /* Check if TPM event log (if present) is covered by PMR. */ + /* + * FIXME: currently commented out as GRUB allocates it in a hole between + * PMR and reserved RAM, due to 2MB resolution of PMR. There are no other + * easy-to-use DMA protection mechanisms that would allow to protect that + * part of memory. TPR (TXT DMA Protection Range) gives 1MB resolution, but + * it still wouldn't be enough. + * + * One possible solution would be for GRUB to allocate log at lower address, + * but this would further increase memory space fragmentation. Another + * option is to align PMR up instead of down, making PMR cover part of + * reserved region, but it is unclear what the consequences may be. + * + * In tboot this issue was resolved by reserving leftover chunks of memory + * in e820 and/or UEFI memory map. This is also a valid solution, but would + * require more changes to GRUB than the ones listed above, as event log is + * allocated much earlier than PMRs. + */ + /* + if ( os_mle->evtlog_addr != 0 && os_mle->evtlog_size != 0 && + !is_in_pmr(os_sinit, os_mle->evtlog_addr, os_mle->evtlog_size, + check_high_pmr) ) + txt_reset(SLAUNCH_ERROR_BUFFER_BEYOND_PMR); + */ +} + +uint32_t txt_early_tests(uint32_t load_base_addr, + uint32_t tgt_base_addr, + uint32_t tgt_end_addr) +{ + void *txt_heap; + struct txt_os_mle_data *os_mle; + struct txt_os_sinit_data *os_sinit; + uint32_t size = tgt_end_addr - tgt_base_addr; + + /* Clear the TXT error registers for a clean start of day */ + write_txt_reg(TXTCR_ERRORCODE, 0); + + txt_heap = _p(read_txt_reg(TXTCR_HEAP_BASE)); + + if ( txt_os_mle_data_size(txt_heap) < sizeof(*os_mle) || + txt_os_sinit_data_size(txt_heap) < sizeof(*os_sinit) ) + txt_reset(SLAUNCH_ERROR_GENERIC); + + os_mle = txt_os_mle_data_start(txt_heap); + os_sinit = txt_os_sinit_data_start(txt_heap); + + verify_pmr_ranges(os_mle, os_sinit, load_base_addr, tgt_base_addr, size); + + return os_mle->boot_params_addr; +} diff --git a/xen/arch/x86/include/asm/intel_txt.h b/xen/arch/x86/include/asm/intel_txt.h index f3d1b8a0c8..e4681c5645 100644 --- a/xen/arch/x86/include/asm/intel_txt.h +++ b/xen/arch/x86/include/asm/intel_txt.h @@ -77,6 +77,8 @@ #ifndef __ASSEMBLY__ +extern bool slaunch_active; + /* We need to differentiate between pre- and post paging enabled. */ #ifdef __XEN_CONFIG_H__ #include @@ -265,4 +267,30 @@ static inline void *txt_sinit_mle_data_start(void *heap) sizeof(uint64_t); } +static inline int is_in_pmr(struct txt_os_sinit_data *os_sinit, uint64_t base, + uint32_t size, int check_high) +{ + /* Check for size overflow. */ + if ( base + size < base ) + txt_reset(SLAUNCH_ERROR_INTEGER_OVERFLOW); + + /* Low range always starts at 0, so its size is also end address. */ + if ( base >= os_sinit->vtd_pmr_lo_base && + base + size <= os_sinit->vtd_pmr_lo_size ) + return 1; + + if ( check_high && os_sinit->vtd_pmr_hi_size != 0 ) + { + if ( os_sinit->vtd_pmr_hi_base + os_sinit->vtd_pmr_hi_size < + os_sinit->vtd_pmr_hi_size ) + txt_reset(SLAUNCH_ERROR_INTEGER_OVERFLOW); + if ( base >= os_sinit->vtd_pmr_hi_base && + base + size <= os_sinit->vtd_pmr_hi_base + + os_sinit->vtd_pmr_hi_size ) + return 1; + } + + return 0; +} + #endif /* __ASSEMBLY__ */ diff --git a/xen/arch/x86/intel_txt.c b/xen/arch/x86/intel_txt.c new file mode 100644 index 0000000000..d23727cc82 --- /dev/null +++ b/xen/arch/x86/intel_txt.c @@ -0,0 +1,11 @@ +#include +#include +#include +#include + +bool __initdata slaunch_active; + +static void __maybe_unused compile_time_checks(void) +{ + BUILD_BUG_ON(sizeof(slaunch_active) != 1); +} From 3bb7bdc7a28e96e183f404bd94430e7e932b26d1 Mon Sep 17 00:00:00 2001 From: Kacper Stojek Date: Fri, 2 Sep 2022 08:11:43 +0200 Subject: [PATCH 23/46] xen/arch/x86: reserve TXT memory TXT heap is marked as reserved in e820 to protect against being allocated and overwritten. Signed-off-by: Kacper Stojek Signed-off-by: Krystian Hebel Signed-off-by: Sergii Dmytruk --- xen/arch/x86/include/asm/intel_txt.h | 42 +++++++++++++ xen/arch/x86/include/asm/mm.h | 3 + xen/arch/x86/intel_txt.c | 94 ++++++++++++++++++++++++++++ xen/arch/x86/setup.c | 12 +++- 4 files changed, 148 insertions(+), 3 deletions(-) diff --git a/xen/arch/x86/include/asm/intel_txt.h b/xen/arch/x86/include/asm/intel_txt.h index e4681c5645..45f6894b1a 100644 --- a/xen/arch/x86/include/asm/intel_txt.h +++ b/xen/arch/x86/include/asm/intel_txt.h @@ -89,6 +89,8 @@ extern bool slaunch_active; #define _txt(x) __va(x) #endif +#include + /* * Always use private space as some of registers are either read-only or not * present in public space. @@ -293,4 +295,44 @@ static inline int is_in_pmr(struct txt_os_sinit_data *os_sinit, uint64_t base, return 0; } +/* + * This helper function is used to map memory using L2 page tables by aligning + * mapped regions to 2MB. This way page allocator (which at this point isn't + * yet initialized) isn't needed for creating new L1 mappings. The function + * also checks and skips memory already mapped by the prebuilt tables. + * + * There is no unmap_l2() because the function is meant to be used for code that + * accesses TXT registers and TXT heap soon after which Xen rebuilds memory + * maps, effectively dropping all existing mappings. + */ +extern int map_l2(unsigned long paddr, unsigned long size); + +/* evt_log is a physical address and the caller must map it to virtual, if + * needed. */ +static inline void find_evt_log(void **evt_log, uint32_t *evt_log_size) +{ + struct txt_os_mle_data *os_mle; + struct slr_table *slrt; + struct slr_entry_log_info *log_info; + + os_mle = txt_os_mle_data_start(_txt(read_txt_reg(TXTCR_HEAP_BASE))); + slrt = _txt(os_mle->slrt); + + log_info = (struct slr_entry_log_info *) + slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_LOG_INFO); + if ( log_info != NULL ) + { + *evt_log = _p(log_info->addr); + *evt_log_size = log_info->size; + } + else + { + *evt_log = NULL; + *evt_log_size = 0; + } +} + +extern void map_txt_mem_regions(void); +extern void protect_txt_mem_regions(void); + #endif /* __ASSEMBLY__ */ diff --git a/xen/arch/x86/include/asm/mm.h b/xen/arch/x86/include/asm/mm.h index 6c7e66ee21..d4bf9faec8 100644 --- a/xen/arch/x86/include/asm/mm.h +++ b/xen/arch/x86/include/asm/mm.h @@ -106,6 +106,9 @@ #define _PGC_need_scrub _PGC_allocated #define PGC_need_scrub PGC_allocated +/* How much of the directmap is prebuilt at compile time. */ +#define PREBUILT_MAP_LIMIT (1 << L2_PAGETABLE_SHIFT) + #ifndef CONFIG_BIGMEM /* * This definition is solely for the use in struct page_info (and diff --git a/xen/arch/x86/intel_txt.c b/xen/arch/x86/intel_txt.c index d23727cc82..368fde1dac 100644 --- a/xen/arch/x86/intel_txt.c +++ b/xen/arch/x86/intel_txt.c @@ -1,7 +1,15 @@ #include #include #include +#include +#include +#include +#include #include +#include +#include + +static uint64_t __initdata txt_heap_base, txt_heap_size; bool __initdata slaunch_active; @@ -9,3 +17,89 @@ static void __maybe_unused compile_time_checks(void) { BUILD_BUG_ON(sizeof(slaunch_active) != 1); } + +int __init map_l2(unsigned long paddr, unsigned long size) +{ + unsigned long aligned_paddr = paddr & ~((1ULL << L2_PAGETABLE_SHIFT) - 1); + unsigned long pages = ((paddr + size) - aligned_paddr); + pages = ROUNDUP(pages, 1ULL << L2_PAGETABLE_SHIFT) >> PAGE_SHIFT; + + if ( (aligned_paddr + pages * PAGE_SIZE) <= PREBUILT_MAP_LIMIT ) + return 0; + + if ( aligned_paddr < PREBUILT_MAP_LIMIT ) { + pages -= (PREBUILT_MAP_LIMIT - aligned_paddr) >> PAGE_SHIFT; + aligned_paddr = PREBUILT_MAP_LIMIT; + } + + return map_pages_to_xen((unsigned long)__va(aligned_paddr), + maddr_to_mfn(aligned_paddr), + pages, PAGE_HYPERVISOR); +} + +void __init map_txt_mem_regions(void) +{ + void *evt_log_addr; + uint32_t evt_log_size; + + map_l2(TXT_PRIV_CONFIG_REGS_BASE, NR_TXT_CONFIG_SIZE); + + txt_heap_base = read_txt_reg(TXTCR_HEAP_BASE); + BUG_ON(txt_heap_base == 0); + + txt_heap_size = read_txt_reg(TXTCR_HEAP_SIZE); + BUG_ON(txt_heap_size == 0); + + map_l2(txt_heap_base, txt_heap_size); + + find_evt_log(&evt_log_addr, &evt_log_size); + if ( evt_log_addr != NULL ) + map_l2((unsigned long)evt_log_addr, evt_log_size); +} + +void __init protect_txt_mem_regions(void) +{ + int rc; + + void *evt_log_addr; + uint32_t evt_log_size; + + uint64_t sinit_base, sinit_size; + + /* TXT Heap */ + BUG_ON(txt_heap_base == 0); + printk("SLAUNCH: reserving TXT heap (%#lx - %#lx)\n", txt_heap_base, + txt_heap_base + txt_heap_size); + rc = reserve_e820_ram(&e820_raw, txt_heap_base, + txt_heap_base + txt_heap_size); + BUG_ON(rc == 0); + + /* TXT TPM Event Log */ + find_evt_log(&evt_log_addr, &evt_log_size); + if ( evt_log_addr != NULL ) { + printk("SLAUNCH: reserving event log (%#lx - %#lx)\n", + (uint64_t)evt_log_addr, + (uint64_t)evt_log_addr + evt_log_size); + rc = reserve_e820_ram(&e820_raw, (uint64_t)evt_log_addr, + (uint64_t)evt_log_addr + evt_log_size); + BUG_ON(rc == 0); + } + + sinit_base = read_txt_reg(TXTCR_SINIT_BASE); + BUG_ON(sinit_base == 0); + + sinit_size = read_txt_reg(TXTCR_SINIT_SIZE); + BUG_ON(sinit_size == 0); + + /* SINIT */ + printk("SLAUNCH: reserving SINIT memory (%#lx - %#lx)\n", sinit_base, + sinit_base + sinit_size); + rc = reserve_e820_ram(&e820_raw, sinit_base, sinit_base + sinit_size); + BUG_ON(rc == 0); + + /* TXT Private Space */ + rc = e820_change_range_type(&e820_raw, TXT_PRIV_CONFIG_REGS_BASE, + TXT_PRIV_CONFIG_REGS_BASE + NR_TXT_CONFIG_SIZE, + E820_RAM, E820_UNUSABLE); + BUG_ON(rc == 0); +} diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 1239e91b83..f7af7b981f 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -62,6 +62,7 @@ #include #include #include +#include /* opt_nosmp: If true, secondary processors are ignored. */ static bool __initdata opt_nosmp; @@ -1048,9 +1049,6 @@ static struct domain *__init create_dom0(struct boot_info *bi) return d; } -/* How much of the directmap is prebuilt at compile time. */ -#define PREBUILT_MAP_LIMIT (1 << L2_PAGETABLE_SHIFT) - void asmlinkage __init noreturn __start_xen(void) { const char *memmap_type = NULL; @@ -1386,6 +1384,14 @@ void asmlinkage __init noreturn __start_xen(void) #endif } + if ( slaunch_active ) + { + /* Prepare for TXT-related code. */ + map_txt_mem_regions(); + /* Reserve TXT heap and SINIT. */ + protect_txt_mem_regions(); + } + /* Sanitise the raw E820 map to produce a final clean version. */ max_page = raw_max_page = init_e820(memmap_type, &e820_raw); From 71830e995bd5a129f4b0b62c83b70ba43d4b3d75 Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Wed, 19 Oct 2022 19:52:24 +0200 Subject: [PATCH 24/46] x86/intel_txt.c: restore boot MTRRs In preparation for TXT SENTER call, GRUB had to modify MTRR settings to be UC for everything except SINIT ACM. Old values are restored from SLRT where they were saved by the bootloader. Signed-off-by: Krystian Hebel Signed-off-by: Sergii Dmytruk --- xen/arch/x86/e820.c | 4 ++ xen/arch/x86/include/asm/intel_txt.h | 1 + xen/arch/x86/intel_txt.c | 59 ++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/xen/arch/x86/e820.c b/xen/arch/x86/e820.c index e052e84de7..c8d14b55a7 100644 --- a/xen/arch/x86/e820.c +++ b/xen/arch/x86/e820.c @@ -11,6 +11,7 @@ #include #include #include +#include /* * opt_mem: Limit maximum address of physical RAM. @@ -455,6 +456,9 @@ static uint64_t __init mtrr_top_of_ram(void) rdmsrl(MSR_MTRRcap, mtrr_cap); rdmsrl(MSR_MTRRdefType, mtrr_def); + if ( slaunch_active ) + txt_restore_mtrrs(e820_verbose); + if ( e820_verbose ) printk(" MTRR cap: %"PRIx64" type: %"PRIx64"\n", mtrr_cap, mtrr_def); diff --git a/xen/arch/x86/include/asm/intel_txt.h b/xen/arch/x86/include/asm/intel_txt.h index 45f6894b1a..86a2415971 100644 --- a/xen/arch/x86/include/asm/intel_txt.h +++ b/xen/arch/x86/include/asm/intel_txt.h @@ -334,5 +334,6 @@ static inline void find_evt_log(void **evt_log, uint32_t *evt_log_size) extern void map_txt_mem_regions(void); extern void protect_txt_mem_regions(void); +extern void txt_restore_mtrrs(bool e820_verbose); #endif /* __ASSEMBLY__ */ diff --git a/xen/arch/x86/intel_txt.c b/xen/arch/x86/intel_txt.c index 368fde1dac..90a3b6c04c 100644 --- a/xen/arch/x86/intel_txt.c +++ b/xen/arch/x86/intel_txt.c @@ -103,3 +103,62 @@ void __init protect_txt_mem_regions(void) E820_RAM, E820_UNUSABLE); BUG_ON(rc == 0); } + +void __init txt_restore_mtrrs(bool e820_verbose) +{ + struct txt_os_mle_data *os_mle; + struct slr_table *slrt; + struct slr_entry_intel_info *intel_info; + int os_mle_size; + uint64_t mtrr_cap, mtrr_def, base, mask; + unsigned int i; + + os_mle_size = txt_os_mle_data_size(__va(txt_heap_base)); + os_mle = txt_os_mle_data_start(__va(txt_heap_base)); + + if ( os_mle_size < sizeof(*os_mle) ) + panic("OS-MLE too small\n"); + + rdmsrl(MSR_MTRRcap, mtrr_cap); + rdmsrl(MSR_MTRRdefType, mtrr_def); + + if ( e820_verbose ) { + printk("MTRRs set previously for SINIT ACM:\n"); + printk(" MTRR cap: %"PRIx64" type: %"PRIx64"\n", mtrr_cap, mtrr_def); + + for ( i = 0; i < (uint8_t)mtrr_cap; i++ ) + { + rdmsrl(MSR_IA32_MTRR_PHYSBASE(i), base); + rdmsrl(MSR_IA32_MTRR_PHYSMASK(i), mask); + + printk(" MTRR[%d]: base %"PRIx64" mask %"PRIx64"\n", + i, base, mask); + } + } + + slrt = __va(os_mle->slrt); + intel_info = (struct slr_entry_intel_info *) + slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_INTEL_INFO); + + if ( (mtrr_cap & 0xFF) != intel_info->saved_bsp_mtrrs.mtrr_vcnt ) { + printk("Bootloader saved %ld MTRR values, but there should be %ld\n", + intel_info->saved_bsp_mtrrs.mtrr_vcnt, mtrr_cap & 0xFF); + /* Choose the smaller one to be on the safe side. */ + mtrr_cap = (mtrr_cap & 0xFF) > intel_info->saved_bsp_mtrrs.mtrr_vcnt ? + intel_info->saved_bsp_mtrrs.mtrr_vcnt : mtrr_cap; + } + + /* Restore MTRRs saved by bootloader. */ + wrmsrl(MSR_MTRRdefType, intel_info->saved_bsp_mtrrs.default_mem_type); + + for ( i = 0; i < (uint8_t)mtrr_cap; i++ ) + { + base = intel_info->saved_bsp_mtrrs.mtrr_pair[i].mtrr_physbase; + mask = intel_info->saved_bsp_mtrrs.mtrr_pair[i].mtrr_physmask; + wrmsrl(MSR_IA32_MTRR_PHYSBASE(i), base); + wrmsrl(MSR_IA32_MTRR_PHYSMASK(i), mask); + } + + if ( e820_verbose ) + printk("Restored MTRRs:\n"); /* Printed by caller, mtrr_top_of_ram(). */ +} From 09760b4e2af0752d055a13753cebba53f50dcb58 Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Tue, 25 Oct 2022 16:04:17 +0200 Subject: [PATCH 25/46] lib/sha1.c: add file The code comes from [1] and is licensed under GPL-2.0 license. It's a combination of: - include/crypto/sha1.h - include/crypto/sha1_base.h - lib/crypto/sha1.c - crypto/sha1_generic.c Changes: - includes - formatting - renames and splicing of trivial some functions that are called once - dropping of `int` return values (only zero was ever returned) - getting rid of references to `struct shash_desc` [1]: https://github.com/torvalds/linux/tree/afdab700f65e14070d8ab92175544b1c62b8bf03 Signed-off-by: Krystian Hebel Signed-off-by: Sergii Dmytruk Signed-off-by: Krystian Hebel --- xen/include/xen/sha1.h | 10 ++ xen/lib/Makefile | 1 + xen/lib/sha1.c | 240 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 251 insertions(+) create mode 100644 xen/include/xen/sha1.h create mode 100644 xen/lib/sha1.c diff --git a/xen/include/xen/sha1.h b/xen/include/xen/sha1.h new file mode 100644 index 0000000000..85be7b3c12 --- /dev/null +++ b/xen/include/xen/sha1.h @@ -0,0 +1,10 @@ +#ifndef __XEN_SHA1_H +#define __XEN_SHA1_H + +#include + +#define SHA1_DIGEST_SIZE 20 + +void sha1_hash(const u8 *data, unsigned int len, u8 *out); + +#endif /* !__XEN_SHA1_H */ diff --git a/xen/lib/Makefile b/xen/lib/Makefile index 54440f628a..9fa289b700 100644 --- a/xen/lib/Makefile +++ b/xen/lib/Makefile @@ -37,6 +37,7 @@ lib-y += strtoll.o lib-y += strtoul.o lib-y += strtoull.o lib-$(CONFIG_X86) += x86-generic-hweightl.o +lib-$(CONFIG_X86) += sha1.o lib-$(CONFIG_X86) += xxhash32.o lib-$(CONFIG_X86) += xxhash64.o diff --git a/xen/lib/sha1.c b/xen/lib/sha1.c new file mode 100644 index 0000000000..a11822519d --- /dev/null +++ b/xen/lib/sha1.c @@ -0,0 +1,240 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * SHA1 routine optimized to do word accesses rather than byte accesses, + * and to avoid unnecessary copies into the context array. + * + * This was based on the git SHA1 implementation. + */ + +#include +#include +#include +#include + +/* + * If you have 32 registers or more, the compiler can (and should) + * try to change the array[] accesses into registers. However, on + * machines with less than ~25 registers, that won't really work, + * and at least gcc will make an unholy mess of it. + * + * So to avoid that mess which just slows things down, we force + * the stores to memory to actually happen (we might be better off + * with a 'W(t)=(val);asm("":"+m" (W(t))' there instead, as + * suggested by Artur Skawina - that will also make gcc unable to + * try to do the silly "optimize away loads" part because it won't + * see what the value will be). + * + * Ben Herrenschmidt reports that on PPC, the C version comes close + * to the optimized asm with this (ie on PPC you don't want that + * 'volatile', since there are lots of registers). + * + * On ARM we get the best code generation by forcing a full memory barrier + * between each SHA_ROUND, otherwise gcc happily get wild with spilling and + * the stack frame size simply explode and performance goes down the drain. + */ + +#ifdef CONFIG_X86 + #define setW(x, val) (*(volatile uint32_t *)&W(x) = (val)) +#elif defined(CONFIG_ARM) + #define setW(x, val) do { W(x) = (val); __asm__("":::"memory"); } while ( 0 ) +#else + #define setW(x, val) (W(x) = (val)) +#endif + +/* This "rolls" over the 512-bit array */ +#define W(x) (array[(x) & 15]) + +/* + * Where do we get the source from? The first 16 iterations get it from + * the input data, the next mix it from the 512-bit array. + */ +#define SHA_SRC(t) get_unaligned_be32((uint32_t *)data + t) +#define SHA_MIX(t) rol32(W(t + 13) ^ W(t + 8) ^ W(t + 2) ^ W(t), 1) + +#define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \ + uint32_t TEMP = input(t); setW(t, TEMP); \ + E += TEMP + rol32(A, 5) + (fn) + (constant); \ + B = ror32(B, 2); \ + TEMP = E; E = D; D = C; C = B; B = A; A = TEMP; \ + } while ( 0 ) + +#define T_0_15(t, A, B, C, D, E) \ + SHA_ROUND(t, SHA_SRC, (((C ^ D) & B) ^ D), 0x5a827999, A, B, C, D, E) +#define T_16_19(t, A, B, C, D, E) \ + SHA_ROUND(t, SHA_MIX, (((C ^ D) & B) ^ D), 0x5a827999, A, B, C, D, E) +#define T_20_39(t, A, B, C, D, E) \ + SHA_ROUND(t, SHA_MIX, (B ^ C ^ D), 0x6ed9eba1, A, B, C, D, E) +#define T_40_59(t, A, B, C, D, E) \ + SHA_ROUND(t, SHA_MIX, ((B & C) + (D & (B ^ C))), 0x8f1bbcdc, A, B, C, \ + D, E) +#define T_60_79(t, A, B, C, D, E) \ + SHA_ROUND(t, SHA_MIX, (B ^ C ^ D), 0xca62c1d6, A, B, C, D, E) + +#define SHA1_BLOCK_SIZE 64 +#define SHA1_WORKSPACE_WORDS 16 + +struct sha1_state { + uint32_t state[SHA1_DIGEST_SIZE / 4]; + uint64_t count; + uint8_t buffer[SHA1_BLOCK_SIZE]; +}; + +typedef void sha1_block_fn(struct sha1_state *sst, const uint8_t *src, int blocks); + +/** + * sha1_transform - single block SHA1 transform (deprecated) + * + * @digest: 160 bit digest to update + * @data: 512 bits of data to hash + * @array: 16 words of workspace (see note) + * + * This function executes SHA-1's internal compression function. It updates the + * 160-bit internal state (@digest) with a single 512-bit data block (@data). + * + * Don't use this function. SHA-1 is no longer considered secure. And even if + * you do have to use SHA-1, this isn't the correct way to hash something with + * SHA-1 as this doesn't handle padding and finalization. + * + * Note: If the hash is security sensitive, the caller should be sure + * to clear the workspace. This is left to the caller to avoid + * unnecessary clears between chained hashing operations. + */ +void sha1_transform(uint32_t *digest, const uint8_t *data, uint32_t *array) +{ + uint32_t A, B, C, D, E; + unsigned int i = 0; + + A = digest[0]; + B = digest[1]; + C = digest[2]; + D = digest[3]; + E = digest[4]; + + /* Round 1 - iterations 0-16 take their input from 'data' */ + for ( ; i < 16; ++i ) + T_0_15(i, A, B, C, D, E); + + /* Round 1 - tail. Input from 512-bit mixing array */ + for ( ; i < 20; ++i ) + T_16_19(i, A, B, C, D, E); + + /* Round 2 */ + for ( ; i < 40; ++i ) + T_20_39(i, A, B, C, D, E); + + /* Round 3 */ + for ( ; i < 60; ++i ) + T_40_59(i, A, B, C, D, E); + + /* Round 4 */ + for ( ; i < 80; ++i ) + T_60_79(i, A, B, C, D, E); + + digest[0] += A; + digest[1] += B; + digest[2] += C; + digest[3] += D; + digest[4] += E; +} + +static void sha1_init(struct sha1_state *sctx) +{ + sctx->state[0] = 0x67452301UL; + sctx->state[1] = 0xefcdab89UL; + sctx->state[2] = 0x98badcfeUL; + sctx->state[3] = 0x10325476UL; + sctx->state[4] = 0xc3d2e1f0UL; + sctx->count = 0; +} + +static void sha1_do_update(struct sha1_state *sctx, + const uint8_t *data, + unsigned int len, + sha1_block_fn *block_fn) +{ + unsigned int partial = sctx->count % SHA1_BLOCK_SIZE; + + sctx->count += len; + + if ( unlikely((partial + len) >= SHA1_BLOCK_SIZE) ) + { + int blocks; + + if ( partial ) + { + int p = SHA1_BLOCK_SIZE - partial; + + memcpy(sctx->buffer + partial, data, p); + data += p; + len -= p; + + block_fn(sctx, sctx->buffer, 1); + } + + blocks = len / SHA1_BLOCK_SIZE; + len %= SHA1_BLOCK_SIZE; + + if ( blocks ) + { + block_fn(sctx, data, blocks); + data += blocks * SHA1_BLOCK_SIZE; + } + partial = 0; + } + if ( len ) + memcpy(sctx->buffer + partial, data, len); +} + +static void sha1_do_finalize(struct sha1_state *sctx, sha1_block_fn *block_fn) +{ + const int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64); + __be64 *bits = (__be64 *)(sctx->buffer + bit_offset); + unsigned int partial = sctx->count % SHA1_BLOCK_SIZE; + + sctx->buffer[partial++] = 0x80; + if ( partial > bit_offset ) + { + memset(sctx->buffer + partial, 0x0, SHA1_BLOCK_SIZE - partial); + partial = 0; + + block_fn(sctx, sctx->buffer, 1); + } + + memset(sctx->buffer + partial, 0x0, bit_offset - partial); + *bits = cpu_to_be64(sctx->count << 3); + block_fn(sctx, sctx->buffer, 1); +} + +static void sha1_finish(struct sha1_state *sctx, uint8_t *out) +{ + __be32 *digest = (__be32 *)out; + int i; + + for ( i = 0; i < SHA1_DIGEST_SIZE / sizeof(__be32); i++ ) + put_unaligned_be32(sctx->state[i], digest++); + + memset(sctx, 0, sizeof(*sctx)); +} + +static void sha1_generic_block_fn(struct sha1_state *sctx, const uint8_t *src, + int blocks) +{ + uint32_t temp[SHA1_WORKSPACE_WORDS]; + + while ( blocks-- ) + { + sha1_transform(sctx->state, src, temp); + src += SHA1_BLOCK_SIZE; + } + memset(temp, 0, sizeof(temp)); +} + +void sha1_hash(const uint8_t *data, unsigned int len, uint8_t *out) +{ + struct sha1_state sctx; + + sha1_init(&sctx); + sha1_do_update(&sctx, data, len, sha1_generic_block_fn); + sha1_do_finalize(&sctx, sha1_generic_block_fn); + sha1_finish(&sctx, out); +} From be1e37c9ff3617bd511070c318425edf864a6c85 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Mon, 26 Jun 2023 00:17:15 +0300 Subject: [PATCH 26/46] lib/sha256.c: add file The code comes from [1] and is licensed under GPL-2.0 or later version of license. It's a combination of: - include/crypto/sha2.h - include/crypto/sha256_base.h - lib/crypto/sha256.c - crypto/sha256_generic.c Changes: - includes - formatting - renames and splicing of trivial some functions that are called once - dropping of `int` return values (only zero was ever returned) - getting rid of references to `struct shash_desc` [1]: https://github.com/torvalds/linux/tree/afdab700f65e14070d8ab92175544b1c62b8bf03 Signed-off-by: Sergii Dmytruk Signed-off-by: Krystian Hebel --- xen/include/xen/sha256.h | 10 ++ xen/lib/Makefile | 1 + xen/lib/sha256.c | 238 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 249 insertions(+) create mode 100644 xen/include/xen/sha256.h create mode 100644 xen/lib/sha256.c diff --git a/xen/include/xen/sha256.h b/xen/include/xen/sha256.h new file mode 100644 index 0000000000..0a483b6fd6 --- /dev/null +++ b/xen/include/xen/sha256.h @@ -0,0 +1,10 @@ +#ifndef __XEN_SHA256_H +#define __XEN_SHA256_H + +#include + +#define SHA256_DIGEST_SIZE 32 + +void sha256_hash(const u8 *data, unsigned int len, u8 *out); + +#endif /* !__XEN_SHA256_H */ diff --git a/xen/lib/Makefile b/xen/lib/Makefile index 9fa289b700..40737c05cd 100644 --- a/xen/lib/Makefile +++ b/xen/lib/Makefile @@ -38,6 +38,7 @@ lib-y += strtoul.o lib-y += strtoull.o lib-$(CONFIG_X86) += x86-generic-hweightl.o lib-$(CONFIG_X86) += sha1.o +lib-$(CONFIG_X86) += sha256.o lib-$(CONFIG_X86) += xxhash32.o lib-$(CONFIG_X86) += xxhash64.o diff --git a/xen/lib/sha256.c b/xen/lib/sha256.c new file mode 100644 index 0000000000..d569efa88c --- /dev/null +++ b/xen/lib/sha256.c @@ -0,0 +1,238 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * SHA-256, as specified in + * http://csrc.nist.gov/groups/STM/cavp/documents/shs/sha256-384-512.pdf + * + * SHA-256 code by Jean-Luc Cooke . + * + * Copyright (c) Jean-Luc Cooke + * Copyright (c) Andrew McDonald + * Copyright (c) 2002 James Morris + * Copyright (c) 2014 Red Hat Inc. + */ + +#include +#include +#include + +#define SHA256_BLOCK_SIZE 64 + +struct sha256_state { + uint32_t state[SHA256_DIGEST_SIZE / 4]; + uint64_t count; + uint8_t buf[SHA256_BLOCK_SIZE]; +}; + +typedef void sha256_block_fn(struct sha256_state *sst, uint8_t const *src, + int blocks); + +static const uint32_t SHA256_K[] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, +}; + +static uint32_t Ch(uint32_t x, uint32_t y, uint32_t z) +{ + return z ^ (x & (y ^ z)); +} + +static uint32_t Maj(uint32_t x, uint32_t y, uint32_t z) +{ + return (x & y) | (z & (x | y)); +} + +#define e0(x) (ror32(x, 2) ^ ror32(x, 13) ^ ror32(x, 22)) +#define e1(x) (ror32(x, 6) ^ ror32(x, 11) ^ ror32(x, 25)) +#define s0(x) (ror32(x, 7) ^ ror32(x, 18) ^ (x >> 3)) +#define s1(x) (ror32(x, 17) ^ ror32(x, 19) ^ (x >> 10)) + +static void LOAD_OP(int I, uint32_t *W, const uint8_t *input) +{ + W[I] = get_unaligned_be32((uint32_t *)input + I); +} + +static void BLEND_OP(int I, uint32_t *W) +{ + W[I] = s1(W[I - 2]) + W[I - 7] + s0(W[I - 15]) + W[I - 16]; +} + +#define SHA256_ROUND(i, a, b, c, d, e, f, g, h) do { \ + uint32_t t1, t2; \ + t1 = h + e1(e) + Ch(e, f, g) + SHA256_K[i] + W[i]; \ + t2 = e0(a) + Maj(a, b, c); \ + d += t1; \ + h = t1 + t2; \ + } while ( 0 ) + +static void sha256_init(struct sha256_state *sctx) +{ + sctx->state[0] = 0x6a09e667UL; + sctx->state[1] = 0xbb67ae85UL; + sctx->state[2] = 0x3c6ef372UL; + sctx->state[3] = 0xa54ff53aUL; + sctx->state[4] = 0x510e527fUL; + sctx->state[5] = 0x9b05688cUL; + sctx->state[6] = 0x1f83d9abUL; + sctx->state[7] = 0x5be0cd19UL; + sctx->count = 0; +} + +static void sha256_do_update(struct sha256_state *sctx, + const uint8_t *data, + unsigned int len, + sha256_block_fn *block_fn) +{ + unsigned int partial = sctx->count % SHA256_BLOCK_SIZE; + + sctx->count += len; + + if ( unlikely((partial + len) >= SHA256_BLOCK_SIZE) ) + { + int blocks; + + if ( partial ) + { + int p = SHA256_BLOCK_SIZE - partial; + + memcpy(sctx->buf + partial, data, p); + data += p; + len -= p; + + block_fn(sctx, sctx->buf, 1); + } + + blocks = len / SHA256_BLOCK_SIZE; + len %= SHA256_BLOCK_SIZE; + + if ( blocks ) + { + block_fn(sctx, data, blocks); + data += blocks * SHA256_BLOCK_SIZE; + } + partial = 0; + } + if ( len ) + memcpy(sctx->buf + partial, data, len); +} + +static void sha256_do_finalize(struct sha256_state *sctx, + sha256_block_fn *block_fn) +{ + const int bit_offset = SHA256_BLOCK_SIZE - sizeof(__be64); + __be64 *bits = (__be64 *)(sctx->buf + bit_offset); + unsigned int partial = sctx->count % SHA256_BLOCK_SIZE; + + sctx->buf[partial++] = 0x80; + if ( partial > bit_offset ) + { + memset(sctx->buf + partial, 0x0, SHA256_BLOCK_SIZE - partial); + partial = 0; + + block_fn(sctx, sctx->buf, 1); + } + + memset(sctx->buf + partial, 0x0, bit_offset - partial); + *bits = cpu_to_be64(sctx->count << 3); + block_fn(sctx, sctx->buf, 1); +} + +static void sha256_finish(struct sha256_state *sctx, uint8_t *out, + unsigned int digest_size) +{ + __be32 *digest = (__be32 *)out; + int i; + + for ( i = 0; digest_size > 0; i++, digest_size -= sizeof(__be32) ) + put_unaligned_be32(sctx->state[i], digest++); + + memset(sctx, 0, sizeof(*sctx)); +} + +static void sha256_transform(uint32_t *state, const uint8_t *input, uint32_t *W) +{ + uint32_t a, b, c, d, e, f, g, h; + int i; + + /* load the input */ + for ( i = 0; i < 16; i += 8 ) + { + LOAD_OP(i + 0, W, input); + LOAD_OP(i + 1, W, input); + LOAD_OP(i + 2, W, input); + LOAD_OP(i + 3, W, input); + LOAD_OP(i + 4, W, input); + LOAD_OP(i + 5, W, input); + LOAD_OP(i + 6, W, input); + LOAD_OP(i + 7, W, input); + } + + /* now blend */ + for ( i = 16; i < 64; i += 8 ) + { + BLEND_OP(i + 0, W); + BLEND_OP(i + 1, W); + BLEND_OP(i + 2, W); + BLEND_OP(i + 3, W); + BLEND_OP(i + 4, W); + BLEND_OP(i + 5, W); + BLEND_OP(i + 6, W); + BLEND_OP(i + 7, W); + } + + /* load the state into our registers */ + a = state[0]; b = state[1]; c = state[2]; d = state[3]; + e = state[4]; f = state[5]; g = state[6]; h = state[7]; + + /* now iterate */ + for ( i = 0; i < 64; i += 8 ) + { + SHA256_ROUND(i + 0, a, b, c, d, e, f, g, h); + SHA256_ROUND(i + 1, h, a, b, c, d, e, f, g); + SHA256_ROUND(i + 2, g, h, a, b, c, d, e, f); + SHA256_ROUND(i + 3, f, g, h, a, b, c, d, e); + SHA256_ROUND(i + 4, e, f, g, h, a, b, c, d); + SHA256_ROUND(i + 5, d, e, f, g, h, a, b, c); + SHA256_ROUND(i + 6, c, d, e, f, g, h, a, b); + SHA256_ROUND(i + 7, b, c, d, e, f, g, h, a); + } + + state[0] += a; state[1] += b; state[2] += c; state[3] += d; + state[4] += e; state[5] += f; state[6] += g; state[7] += h; +} + +static void sha256_transform_blocks(struct sha256_state *sctx, + const uint8_t *input, int blocks) +{ + uint32_t W[64]; + + do { + sha256_transform(sctx->state, input, W); + input += SHA256_BLOCK_SIZE; + } while ( --blocks ); + + memset(W, 0, sizeof(W)); +} + +void sha256_hash(const uint8_t *data, unsigned int len, uint8_t *out) +{ + struct sha256_state sctx; + + sha256_init(&sctx); + sha256_do_update(&sctx, data, len, sha256_transform_blocks); + sha256_do_finalize(&sctx, sha256_transform_blocks); + sha256_finish(&sctx, out, SHA256_DIGEST_SIZE); +} From b5ce0c0ce4b69b7c476d569983ddfeb70e36e63a Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Fri, 21 Oct 2022 18:46:33 +0200 Subject: [PATCH 27/46] x86/tpm.c: code for early hashing and extending PCRs (for TPM1.2) This file is built twice: for early 32b mode without paging to measure MBI and for 64b code to measure dom0 kernel and initramfs. Since MBI is small, the first case uses TPM to do the hashing. Kernel and initramfs on the other hand are too big, sending them to the TPM would take multiple minutes. Signed-off-by: Krystian Hebel Signed-off-by: Sergii Dmytruk --- xen/arch/x86/Makefile | 1 + xen/arch/x86/boot/Makefile | 7 +- xen/arch/x86/boot/head.S | 9 +- xen/arch/x86/include/asm/intel_txt.h | 29 +- xen/arch/x86/include/asm/tpm.h | 12 + xen/arch/x86/intel_txt.c | 7 +- xen/arch/x86/tpm.c | 434 +++++++++++++++++++++++++++ 7 files changed, 487 insertions(+), 12 deletions(-) create mode 100644 xen/arch/x86/include/asm/tpm.h create mode 100644 xen/arch/x86/tpm.c diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index c0f2c72781..f0fce48454 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -66,6 +66,7 @@ obj-y += spec_ctrl.o obj-y += srat.o obj-y += string.o obj-y += time.o +obj-y += tpm.o obj-y += traps.o obj-$(CONFIG_INTEL) += tsx.o obj-y += usercopy.o diff --git a/xen/arch/x86/boot/Makefile b/xen/arch/x86/boot/Makefile index f5c30ace4d..6a9e27b18a 100644 --- a/xen/arch/x86/boot/Makefile +++ b/xen/arch/x86/boot/Makefile @@ -6,6 +6,7 @@ obj32 := cmdline.32.o obj32 += reloc.32.o obj32 += reloc-trampoline.32.o obj32 += txt_early.32.o +obj32 += tpm_early.32.o obj64 := reloc-trampoline.o @@ -28,6 +29,10 @@ $(obj32): XEN_CFLAGS := $(CFLAGS_x86_32) -fpic $(obj)/%.32.o: $(src)/%.c FORCE $(call if_changed_rule,cc_o_c) +$(obj)/tpm_early.32.o: XEN_CFLAGS += -D__EARLY_TPM__ +$(obj)/tpm_early.32.o: $(src)/../tpm.c FORCE + $(call if_changed_rule,cc_o_c) + orphan-handling-$(call ld-option,--orphan-handling=error) := --orphan-handling=error LDFLAGS_DIRECT-$(call ld-option,--warn-rwx-segments) := --no-warn-rwx-segments LDFLAGS_DIRECT += $(LDFLAGS_DIRECT-y) @@ -81,7 +86,7 @@ cmd_combine = \ --bin1 $(obj)/built-in-32.base.bin \ --bin2 $(obj)/built-in-32.offset.bin \ --map $(obj)/built-in-32.base.map \ - --exports cmdline_parse_early,reloc,reloc_trampoline32,txt_early_tests \ + --exports cmdline_parse_early,reloc,reloc_trampoline32,txt_early_tests,tpm_extend_mbi \ --output $@ targets += built-in-32.S diff --git a/xen/arch/x86/boot/head.S b/xen/arch/x86/boot/head.S index e63226e09c..2a60bb0b8d 100644 --- a/xen/arch/x86/boot/head.S +++ b/xen/arch/x86/boot/head.S @@ -501,10 +501,13 @@ __start: call txt_early_tests /* - * txt_early_tests() returns MBI address, move it to EBX, move magic - * number expected by Multiboot 2 to EAX and fall through. + * txt_early_tests() returns MBI address, pass it to tpm_extend_mbi() + * and store for later in EBX. */ - movl %eax,%ebx + movl %eax, %ebx + call tpm_extend_mbi + + /* Move magic number expected by Multiboot 2 to EAX and fall through. */ movl $MULTIBOOT2_BOOTLOADER_MAGIC,%eax .Lmultiboot2_proto: diff --git a/xen/arch/x86/include/asm/intel_txt.h b/xen/arch/x86/include/asm/intel_txt.h index 86a2415971..be428402b1 100644 --- a/xen/arch/x86/include/asm/intel_txt.h +++ b/xen/arch/x86/include/asm/intel_txt.h @@ -309,15 +309,11 @@ extern int map_l2(unsigned long paddr, unsigned long size); /* evt_log is a physical address and the caller must map it to virtual, if * needed. */ -static inline void find_evt_log(void **evt_log, uint32_t *evt_log_size) +static inline void find_evt_log(struct slr_table *slrt, void **evt_log, + uint32_t *evt_log_size) { - struct txt_os_mle_data *os_mle; - struct slr_table *slrt; struct slr_entry_log_info *log_info; - os_mle = txt_os_mle_data_start(_txt(read_txt_reg(TXTCR_HEAP_BASE))); - slrt = _txt(os_mle->slrt); - log_info = (struct slr_entry_log_info *) slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_LOG_INFO); if ( log_info != NULL ) @@ -332,8 +328,29 @@ static inline void find_evt_log(void **evt_log, uint32_t *evt_log_size) } } +/* Returns physical address. */ +static inline uint32_t txt_find_slrt(void) +{ + struct txt_os_mle_data *os_mle = + txt_os_mle_data_start(_txt(read_txt_reg(TXTCR_HEAP_BASE))); + return os_mle->slrt; +} + extern void map_txt_mem_regions(void); extern void protect_txt_mem_regions(void); extern void txt_restore_mtrrs(bool e820_verbose); +#define DRTM_LOC 2 +#define DRTM_CODE_PCR 17 +#define DRTM_DATA_PCR 18 + +/* + * Secure Launch event log entry type. The TXT specification defines the + * base event value as 0x400 for DRTM values. + */ +#define TXT_EVTYPE_BASE 0x400 +#define TXT_EVTYPE_SLAUNCH (TXT_EVTYPE_BASE + 0x102) +#define TXT_EVTYPE_SLAUNCH_START (TXT_EVTYPE_BASE + 0x103) +#define TXT_EVTYPE_SLAUNCH_END (TXT_EVTYPE_BASE + 0x104) + #endif /* __ASSEMBLY__ */ diff --git a/xen/arch/x86/include/asm/tpm.h b/xen/arch/x86/include/asm/tpm.h new file mode 100644 index 0000000000..9bbdf63680 --- /dev/null +++ b/xen/arch/x86/include/asm/tpm.h @@ -0,0 +1,12 @@ +#ifndef _ASM_X86_TPM_H_ +#define _ASM_X86_TPM_H_ + +#include + +#define TPM_TIS_BASE 0xFED40000 +#define TPM_TIS_SIZE 0x00010000 + +void tpm_hash_extend(unsigned loc, unsigned pcr, uint8_t *buf, unsigned size, + uint32_t type, uint8_t *log_data, unsigned log_data_size); + +#endif /* _ASM_X86_TPM_H_ */ diff --git a/xen/arch/x86/intel_txt.c b/xen/arch/x86/intel_txt.c index 90a3b6c04c..f07a1044ee 100644 --- a/xen/arch/x86/intel_txt.c +++ b/xen/arch/x86/intel_txt.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,7 @@ void __init map_txt_mem_regions(void) uint32_t evt_log_size; map_l2(TXT_PRIV_CONFIG_REGS_BASE, NR_TXT_CONFIG_SIZE); + map_l2(TPM_TIS_BASE, TPM_TIS_SIZE); txt_heap_base = read_txt_reg(TXTCR_HEAP_BASE); BUG_ON(txt_heap_base == 0); @@ -52,7 +54,8 @@ void __init map_txt_mem_regions(void) map_l2(txt_heap_base, txt_heap_size); - find_evt_log(&evt_log_addr, &evt_log_size); + find_evt_log(__va(txt_find_slrt()), &evt_log_addr, &evt_log_size); + map_l2((unsigned long)evt_log_addr, evt_log_size); if ( evt_log_addr != NULL ) map_l2((unsigned long)evt_log_addr, evt_log_size); } @@ -75,7 +78,7 @@ void __init protect_txt_mem_regions(void) BUG_ON(rc == 0); /* TXT TPM Event Log */ - find_evt_log(&evt_log_addr, &evt_log_size); + find_evt_log(__va(txt_find_slrt()), &evt_log_addr, &evt_log_size); if ( evt_log_addr != NULL ) { printk("SLAUNCH: reserving event log (%#lx - %#lx)\n", (uint64_t)evt_log_addr, diff --git a/xen/arch/x86/tpm.c b/xen/arch/x86/tpm.c new file mode 100644 index 0000000000..a6f0248531 --- /dev/null +++ b/xen/arch/x86/tpm.c @@ -0,0 +1,434 @@ +/* + * Copyright (c) 2022-2024 3mdeb Sp. z o.o. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include +#include +#include +#include + +#ifdef __EARLY_TPM__ + +#ifdef __va +#error "__va defined in non-paged mode!" +#endif + +#define __va(x) _p(x) + +/* + * The code is being compiled as a standalone binary without linking to any + * other part of Xen. Providing implementation of builtin functions in this + * case is necessary if compiler chooses to not use an inline builtin. + */ +void *memcpy(void *dest, const void *src, size_t n) +{ + const uint8_t *s = src; + uint8_t *d = dest; + + while ( n-- ) + *d++ = *s++; + + return dest; +} + +#else /* __EARLY_TPM__ */ + +#include +#include + +#endif /* __EARLY_TPM__ */ + +#define TPM_LOC_REG(loc, reg) (0x1000 * (loc) + (reg)) + +#define TPM_ACCESS_(x) TPM_LOC_REG(x, 0x00) +#define ACCESS_REQUEST_USE (1 << 1) +#define ACCESS_ACTIVE_LOCALITY (1 << 5) +#define TPM_INTF_CAPABILITY_(x) TPM_LOC_REG(x, 0x14) +#define INTF_VERSION_MASK 0x70000000 +#define TPM_STS_(x) TPM_LOC_REG(x, 0x18) +#define TPM_FAMILY_MASK 0x0C000000 +#define STS_DATA_AVAIL (1 << 4) +#define STS_TPM_GO (1 << 5) +#define STS_COMMAND_READY (1 << 6) +#define STS_VALID (1 << 7) +#define TPM_DATA_FIFO_(x) TPM_LOC_REG(x, 0x24) + +#define swap16(x) __builtin_bswap16(x) +#define swap32(x) __builtin_bswap32(x) +#define memcpy(d, s, n) __builtin_memcpy(d, s, n) + +static inline volatile uint32_t tis_read32(unsigned reg) +{ + return *(volatile uint32_t *)__va(TPM_TIS_BASE + reg); +} + +static inline volatile uint8_t tis_read8(unsigned reg) +{ + return *(volatile uint8_t *)__va(TPM_TIS_BASE + reg); +} + +static inline void tis_write8(unsigned reg, uint8_t val) +{ + *(volatile uint8_t *)__va(TPM_TIS_BASE + reg) = val; +} + +static inline void request_locality(unsigned loc) +{ + tis_write8(TPM_ACCESS_(loc), ACCESS_REQUEST_USE); + /* Check that locality was actually activated. */ + while ( (tis_read8(TPM_ACCESS_(loc)) & ACCESS_ACTIVE_LOCALITY) == 0 ); +} + +static inline void relinquish_locality(unsigned loc) +{ + tis_write8(TPM_ACCESS_(loc), ACCESS_ACTIVE_LOCALITY); +} + +static void send_cmd(unsigned loc, uint8_t *buf, unsigned i_size, + unsigned *o_size) +{ + /* + * Value of "data available" bit counts only when "valid" field is set as + * well. + */ + const unsigned data_avail = STS_VALID | STS_DATA_AVAIL; + + unsigned i; + + /* Make sure TPM can accept a command. */ + if ( (tis_read8(TPM_STS_(loc)) & STS_COMMAND_READY) == 0 ) { + /* Abort current command. */ + tis_write8(TPM_STS_(loc), STS_COMMAND_READY); + /* Wait until TPM is ready for a new one. */ + while ( (tis_read8(TPM_STS_(loc)) & STS_COMMAND_READY) == 0 ); + } + + for ( i = 0; i < i_size; i++ ) + tis_write8(TPM_DATA_FIFO_(loc), buf[i]); + + tis_write8(TPM_STS_(loc), STS_TPM_GO); + + /* Wait for the first byte of response. */ + while ( (tis_read8(TPM_STS_(loc)) & data_avail) != data_avail); + + for ( i = 0; i < *o_size && tis_read8(TPM_STS_(loc)) & data_avail; i++ ) + buf[i] = tis_read8(TPM_DATA_FIFO_(loc)); + + if ( i < *o_size ) + *o_size = i; + + tis_write8(TPM_STS_(loc), STS_COMMAND_READY); +} + +static inline bool is_tpm12(void) +{ + /* + * If one of these conditions is true: + * - INTF_CAPABILITY_x.interfaceVersion is 0 (TIS <= 1.21) + * - INTF_CAPABILITY_x.interfaceVersion is 2 (TIS == 1.3) + * - STS_x.tpmFamily is 0 + * we're dealing with TPM1.2. + */ + uint32_t intf_version = tis_read32(TPM_INTF_CAPABILITY_(0)) + & INTF_VERSION_MASK; + return (intf_version == 0x00000000 || intf_version == 0x20000000 || + (tis_read32(TPM_STS_(0)) & TPM_FAMILY_MASK) == 0); +} + +/****************************** TPM1.2 specific *******************************/ +#define TPM_ORD_Extend 0x00000014 +#define TPM_ORD_SHA1Start 0x000000A0 +#define TPM_ORD_SHA1Update 0x000000A1 +#define TPM_ORD_SHA1CompleteExtend 0x000000A3 + +#define TPM_TAG_RQU_COMMAND 0x00C1 +#define TPM_TAG_RSP_COMMAND 0x00C4 + +/* All fields of following structs are big endian. */ +struct tpm_cmd_hdr { + uint16_t tag; + uint32_t paramSize; + uint32_t ordinal; +} __packed; + +struct tpm_rsp_hdr { + uint16_t tag; + uint32_t paramSize; + uint32_t returnCode; +} __packed; + +struct extend_cmd { + struct tpm_cmd_hdr h; + uint32_t pcrNum; + uint8_t inDigest[SHA1_DIGEST_SIZE]; +} __packed; + +struct extend_rsp { + struct tpm_rsp_hdr h; + uint8_t outDigest[SHA1_DIGEST_SIZE]; +} __packed; + +struct sha1_start_cmd { + struct tpm_cmd_hdr h; +} __packed; + +struct sha1_start_rsp { + struct tpm_rsp_hdr h; + uint32_t maxNumBytes; +} __packed; + +struct sha1_update_cmd { + struct tpm_cmd_hdr h; + uint32_t numBytes; /* Must be a multiple of 64 */ + uint8_t hashData[]; +} __packed; + +struct sha1_update_rsp { + struct tpm_rsp_hdr h; +} __packed; + +struct sha1_complete_extend_cmd { + struct tpm_cmd_hdr h; + uint32_t pcrNum; + uint32_t hashDataSize; /* 0-64, inclusive */ + uint8_t hashData[]; +} __packed; + +struct sha1_complete_extend_rsp { + struct tpm_rsp_hdr h; + uint8_t hashValue[SHA1_DIGEST_SIZE]; + uint8_t outDigest[SHA1_DIGEST_SIZE]; +} __packed; + +struct TPM12_PCREvent { + uint32_t PCRIndex; + uint32_t Type; + uint8_t Digest[SHA1_DIGEST_SIZE]; + uint32_t Size; + uint8_t Data[]; +}; + +struct txt_ev_log_container_12 { + char Signature[20]; /* "TXT Event Container", null-terminated */ + uint8_t Reserved[12]; + uint8_t ContainerVerMajor; + uint8_t ContainerVerMinor; + uint8_t PCREventVerMajor; + uint8_t PCREventVerMinor; + uint32_t ContainerSize; /* Allocated size */ + uint32_t PCREventsOffset; + uint32_t NextEventOffset; + struct TPM12_PCREvent PCREvents[]; +}; + +#ifdef __EARLY_TPM__ +/* + * TPM1.2 is required to support commands of up to 1101 bytes, vendors rarely + * go above that. Limit maximum size of block of data to be hashed to 1024. + */ +#define MAX_HASH_BLOCK 1024 +#define CMD_RSP_BUF_SIZE (sizeof(struct sha1_update_cmd) + MAX_HASH_BLOCK) + +union cmd_rsp { + struct sha1_start_cmd start_c; + struct sha1_start_rsp start_r; + struct sha1_update_cmd update_c; + struct sha1_update_rsp update_r; + struct sha1_complete_extend_cmd finish_c; + struct sha1_complete_extend_rsp finish_r; + uint8_t buf[CMD_RSP_BUF_SIZE]; +}; + +/* Returns true on success. */ +static bool tpm12_hash_extend(unsigned loc, uint8_t *buf, unsigned size, + unsigned pcr, uint8_t *out_digest) +{ + union cmd_rsp cmd_rsp; + unsigned max_bytes = MAX_HASH_BLOCK; + unsigned o_size = sizeof(cmd_rsp); + bool success = false; + + request_locality(loc); + + cmd_rsp.start_c = (struct sha1_start_cmd) { + .h.tag = swap16(TPM_TAG_RQU_COMMAND), + .h.paramSize = swap32(sizeof(struct sha1_start_cmd)), + .h.ordinal = swap32(TPM_ORD_SHA1Start), + }; + + send_cmd(loc, cmd_rsp.buf, sizeof(struct sha1_start_cmd), &o_size); + if ( o_size < sizeof(struct sha1_start_rsp) ) + goto error; + + if ( max_bytes > swap32(cmd_rsp.start_r.maxNumBytes) ) + max_bytes = swap32(cmd_rsp.start_r.maxNumBytes); + + while ( size > 64 ) { + if ( size < max_bytes ) + max_bytes = size & ~(64 - 1); + + o_size = sizeof(cmd_rsp); + + cmd_rsp.update_c = (struct sha1_update_cmd){ + .h.tag = swap16(TPM_TAG_RQU_COMMAND), + .h.paramSize = swap32(sizeof(struct sha1_update_cmd) + max_bytes), + .h.ordinal = swap32(TPM_ORD_SHA1Update), + .numBytes = swap32(max_bytes), + }; + memcpy(cmd_rsp.update_c.hashData, buf, max_bytes); + + send_cmd(loc, cmd_rsp.buf, sizeof(struct sha1_update_cmd) + max_bytes, + &o_size); + if ( o_size < sizeof(struct sha1_update_rsp) ) + goto error; + + size -= max_bytes; + buf += max_bytes; + } + + o_size = sizeof(cmd_rsp); + + cmd_rsp.finish_c = (struct sha1_complete_extend_cmd) { + .h.tag = swap16(TPM_TAG_RQU_COMMAND), + .h.paramSize = swap32(sizeof(struct sha1_complete_extend_cmd) + size), + .h.ordinal = swap32(TPM_ORD_SHA1CompleteExtend), + .pcrNum = swap32(pcr), + .hashDataSize = swap32(size), + }; + memcpy(cmd_rsp.finish_c.hashData, buf, size); + + send_cmd(loc, cmd_rsp.buf, sizeof(struct sha1_complete_extend_cmd) + size, + &o_size); + if ( o_size < sizeof(struct sha1_complete_extend_rsp) ) + goto error; + + if ( out_digest != NULL ) + memcpy(out_digest, cmd_rsp.finish_r.hashValue, SHA1_DIGEST_SIZE); + + success = true; + +error: + relinquish_locality(loc); + return success; +} + +#else + +union cmd_rsp { + struct extend_cmd extend_c; + struct extend_rsp extend_r; +}; + +/* Returns true on success. */ +static bool tpm12_hash_extend(unsigned loc, uint8_t *buf, unsigned size, + unsigned pcr, uint8_t *out_digest) +{ + union cmd_rsp cmd_rsp; + unsigned o_size = sizeof(cmd_rsp); + + sha1_hash(buf, size, out_digest); + + request_locality(loc); + + cmd_rsp.extend_c = (struct extend_cmd) { + .h.tag = swap16(TPM_TAG_RQU_COMMAND), + .h.paramSize = swap32(sizeof(struct extend_cmd)), + .h.ordinal = swap32(TPM_ORD_Extend), + .pcrNum = swap32(pcr), + }; + + memcpy(cmd_rsp.extend_c.inDigest, out_digest, SHA1_DIGEST_SIZE); + + send_cmd(loc, (uint8_t *)&cmd_rsp, sizeof(struct extend_cmd), &o_size); + + relinquish_locality(loc); + + return (o_size >= sizeof(struct extend_rsp)); +} + +#endif /* __EARLY_TPM__ */ + +static void *create_log_event12(struct txt_ev_log_container_12 *evt_log, + uint32_t evt_log_size, uint32_t pcr, + uint32_t type, uint8_t *data, + unsigned data_size) +{ + struct TPM12_PCREvent *new_entry; + + new_entry = (void *)(((uint8_t *)evt_log) + evt_log->NextEventOffset); + + /* + * Check if there is enough space left for new entry. + * Note: it is possible to introduce a gap in event log if entry with big + * data_size is followed by another entry with smaller data. Maybe we should + * cap the event log size in such case? + */ + if ( evt_log->NextEventOffset + sizeof(struct TPM12_PCREvent) + data_size + > evt_log_size ) + return NULL; + + evt_log->NextEventOffset += sizeof(struct TPM12_PCREvent) + data_size; + + new_entry->PCRIndex = pcr; + new_entry->Type = type; + new_entry->Size = data_size; + + if ( data && data_size > 0 ) + memcpy(new_entry->Data, data, data_size); + + return new_entry->Digest; +} + +/************************** end of TPM1.2 specific ****************************/ + +void tpm_hash_extend(unsigned loc, unsigned pcr, uint8_t *buf, unsigned size, + uint32_t type, uint8_t *log_data, unsigned log_data_size) +{ + void *evt_log_addr; + uint32_t evt_log_size; + + struct slr_table *slrt = __va(txt_find_slrt()); + + find_evt_log(slrt, &evt_log_addr, &evt_log_size); + evt_log_addr = __va((uintptr_t)evt_log_addr); + + if ( is_tpm12() ) { + uint8_t sha1_digest[SHA1_DIGEST_SIZE]; + + struct txt_ev_log_container_12 *evt_log = evt_log_addr; + void *entry_digest = create_log_event12(evt_log, evt_log_size, pcr, + type, log_data, log_data_size); + + /* We still need to write computed hash somewhere. */ + if ( entry_digest == NULL ) + entry_digest = sha1_digest; + + if ( !tpm12_hash_extend(loc, buf, size, pcr, entry_digest) ) { +#ifndef __EARLY_TPM__ + printk(XENLOG_ERR "Extending PCR%u failed\n", pcr); +#endif + } + } +} + +#ifdef __EARLY_TPM__ +void tpm_extend_mbi(uint32_t *mbi) +{ + /* MBI starts with uint32_t total_size. */ + tpm_hash_extend(DRTM_LOC, DRTM_DATA_PCR, (uint8_t *)mbi, *mbi, + TXT_EVTYPE_SLAUNCH, NULL, 0); +} +#endif From 1a360da9985f3fa0d810dfefd7beb3b55a80df0d Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Wed, 28 Jun 2023 20:23:24 +0300 Subject: [PATCH 28/46] x86/tpm.c: support extending PCRs of TPM2.0 SHA1 and SHA256 is hardcoded here, but their support by TPM is checked for. Addition of event log for TPM2.0 will generalize the code further. Signed-off-by: Sergii Dmytruk --- xen/arch/x86/tpm.c | 446 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 434 insertions(+), 12 deletions(-) diff --git a/xen/arch/x86/tpm.c b/xen/arch/x86/tpm.c index a6f0248531..5bfba8a1f9 100644 --- a/xen/arch/x86/tpm.c +++ b/xen/arch/x86/tpm.c @@ -16,6 +16,7 @@ */ #include +#include #include #include #include @@ -33,6 +34,15 @@ * other part of Xen. Providing implementation of builtin functions in this * case is necessary if compiler chooses to not use an inline builtin. */ +void *memset(void *dest, int c, size_t n) +{ + uint8_t *d = dest; + + while ( n-- ) + *d++ = c; + + return dest; +} void *memcpy(void *dest, const void *src, size_t n) { const uint8_t *s = src; @@ -68,6 +78,7 @@ void *memcpy(void *dest, const void *src, size_t n) #define swap16(x) __builtin_bswap16(x) #define swap32(x) __builtin_bswap32(x) +#define memset(s, c, n) __builtin_memset(s, c, n) #define memcpy(d, s, n) __builtin_memcpy(d, s, n) static inline volatile uint32_t tis_read32(unsigned reg) @@ -148,14 +159,15 @@ static inline bool is_tpm12(void) (tis_read32(TPM_STS_(0)) & TPM_FAMILY_MASK) == 0); } -/****************************** TPM1.2 specific *******************************/ -#define TPM_ORD_Extend 0x00000014 -#define TPM_ORD_SHA1Start 0x000000A0 -#define TPM_ORD_SHA1Update 0x000000A1 -#define TPM_ORD_SHA1CompleteExtend 0x000000A3 +/****************************** TPM1.2 & TPM2.0 *******************************/ -#define TPM_TAG_RQU_COMMAND 0x00C1 -#define TPM_TAG_RSP_COMMAND 0x00C4 +/* + * TPM1.2 is required to support commands of up to 1101 bytes, vendors rarely + * go above that. Limit maximum size of block of data to be hashed to 1024. + * + * TPM2.0 should support hashing of at least 1024 bytes. + */ +#define MAX_HASH_BLOCK 1024 /* All fields of following structs are big endian. */ struct tpm_cmd_hdr { @@ -170,6 +182,17 @@ struct tpm_rsp_hdr { uint32_t returnCode; } __packed; +/****************************** TPM1.2 specific *******************************/ + +#define TPM_ORD_Extend 0x00000014 +#define TPM_ORD_SHA1Start 0x000000A0 +#define TPM_ORD_SHA1Update 0x000000A1 +#define TPM_ORD_SHA1CompleteExtend 0x000000A3 + +#define TPM_TAG_RQU_COMMAND 0x00C1 +#define TPM_TAG_RSP_COMMAND 0x00C4 + +/* All fields of following structs are big endian. */ struct extend_cmd { struct tpm_cmd_hdr h; uint32_t pcrNum; @@ -235,11 +258,6 @@ struct txt_ev_log_container_12 { }; #ifdef __EARLY_TPM__ -/* - * TPM1.2 is required to support commands of up to 1101 bytes, vendors rarely - * go above that. Limit maximum size of block of data to be hashed to 1024. - */ -#define MAX_HASH_BLOCK 1024 #define CMD_RSP_BUF_SIZE (sizeof(struct sha1_update_cmd) + MAX_HASH_BLOCK) union cmd_rsp { @@ -394,6 +412,382 @@ static void *create_log_event12(struct txt_ev_log_container_12 *evt_log, /************************** end of TPM1.2 specific ****************************/ +/****************************** TPM2.0 specific *******************************/ + +/* + * These constants are for TPM2.0 but don't have a distinct prefix to match + * names in the specification. + */ + +#define TPM_HT_PCR 0x00 + +#define TPM_RH_NULL 0x40000007 +#define TPM_RS_PW 0x40000009 + +#define HR_SHIFT 24 +#define HR_PCR (TPM_HT_PCR << HR_SHIFT) + +#define TPM_ST_NO_SESSIONS 0x8001 +#define TPM_ST_SESSIONS 0x8002 + +#define TPM_ALG_SHA1 0x0004 +#define TPM_ALG_SHA256 0x000b +#define TPM_ALG_NULL 0x0010 + +#define TPM2_PCR_Extend 0x00000182 +#define TPM2_PCR_HashSequenceStart 0x00000186 +#define TPM2_PCR_SequenceUpdate 0x0000015C +#define TPM2_PCR_EventSequenceComplete 0x00000185 + +#define PUT_BYTES(p, bytes, size) do { \ + memcpy((p), (bytes), (size)); \ + (p) += (size); \ + } while ( 0 ) + +#define PUT_16BIT(p, data) do { \ + *(uint16_t *)(p) = swap16(data); \ + (p) += 2; \ + } while ( 0 ) + +/* All fields of following structs are big endian. */ +struct tpm2_session_header { + uint32_t handle; + uint16_t nonceSize; + uint8_t nonce[0]; + uint8_t attrs; + uint16_t hmacSize; + uint8_t hmac[0]; +} __packed; + +struct tpm2_extend_cmd { + struct tpm_cmd_hdr h; + uint32_t pcrHandle; + uint32_t sessionHdrSize; + struct tpm2_session_header pcrSession; + uint32_t hashCount; + uint8_t hashes[0]; +} __packed; + +struct tpm2_extend_rsp { + struct tpm_rsp_hdr h; +} __packed; + +struct tpm2_sequence_start_cmd { + struct tpm_cmd_hdr h; + uint16_t hmacSize; + uint8_t hmac[0]; + uint16_t hashAlg; +} __packed; + +struct tpm2_sequence_start_rsp { + struct tpm_rsp_hdr h; + uint32_t sequenceHandle; +} __packed; + +struct tpm2_sequence_update_cmd { + struct tpm_cmd_hdr h; + uint32_t sequenceHandle; + uint32_t sessionHdrSize; + struct tpm2_session_header session; + uint16_t dataSize; + uint8_t data[0]; +} __packed; + +struct tpm2_sequence_update_rsp { + struct tpm_rsp_hdr h; +} __packed; + +struct tpm2_sequence_complete_cmd { + struct tpm_cmd_hdr h; + uint32_t pcrHandle; + uint32_t sequenceHandle; + uint32_t sessionHdrSize; + struct tpm2_session_header pcrSession; + struct tpm2_session_header sequenceSession; + uint16_t dataSize; + uint8_t data[0]; +} __packed; + +struct tpm2_sequence_complete_rsp { + struct tpm_rsp_hdr h; + uint32_t paramSize; + uint32_t hashCount; + uint8_t hashes[0]; + /* + * Each hash is represented as: + * struct { + * uint16_t hashAlg; + * uint8_t hash[size of hashAlg]; + * }; + */ +} __packed; + +/* + * These two structure are for convenience, they don't correspond to anything in + * any spec. + */ +struct tpm2_log_hash { + uint16_t alg; /* TPM_ALG_* */ + uint16_t size; + uint8_t *data; /* Non-owning reference to a buffer inside log entry. */ +}; +/* Should be more than enough for now and awhile in the future. */ +#define MAX_HASH_COUNT 8 +struct tpm2_log_hashes { + uint32_t count; + struct tpm2_log_hash hashes[MAX_HASH_COUNT]; +}; + +#ifdef __EARLY_TPM__ + +union tpm2_cmd_rsp { + uint8_t b[sizeof(struct tpm2_sequence_update_cmd) + MAX_HASH_BLOCK]; + struct tpm_cmd_hdr c; + struct tpm_rsp_hdr r; + struct tpm2_sequence_start_cmd start_c; + struct tpm2_sequence_start_rsp start_r; + struct tpm2_sequence_update_cmd update_c; + struct tpm2_sequence_update_rsp update_r; + struct tpm2_sequence_complete_cmd finish_c; + struct tpm2_sequence_complete_rsp finish_r; +}; + +static uint32_t tpm2_hash_extend(unsigned loc, uint8_t *buf, unsigned size, + unsigned pcr, + struct tpm2_log_hashes *log_hashes) +{ + uint32_t seq_handle; + unsigned max_bytes = MAX_HASH_BLOCK; + + union tpm2_cmd_rsp cmd_rsp; + unsigned o_size; + unsigned i; + uint8_t *p; + uint32_t rc; + + cmd_rsp.start_c = (struct tpm2_sequence_start_cmd) { + .h.tag = swap16(TPM_ST_NO_SESSIONS), + .h.paramSize = swap32(sizeof(cmd_rsp.start_c)), + .h.ordinal = swap32(TPM2_PCR_HashSequenceStart), + .hashAlg = swap16(TPM_ALG_NULL), /* Compute all supported hashes. */ + }; + + request_locality(loc); + + o_size = sizeof(cmd_rsp); + send_cmd(loc, cmd_rsp.b, swap32(cmd_rsp.c.paramSize), &o_size); + + if ( cmd_rsp.r.tag == swap16(TPM_ST_NO_SESSIONS) && + cmd_rsp.r.paramSize == swap32(10) ) { + rc = swap32(cmd_rsp.r.returnCode); + if ( rc != 0 ) + goto error; + } + + seq_handle = swap32(cmd_rsp.start_r.sequenceHandle); + + while ( size > 64 ) { + if ( size < max_bytes ) + max_bytes = size & ~(64 - 1); + + cmd_rsp.update_c = (struct tpm2_sequence_update_cmd) { + .h.tag = swap16(TPM_ST_SESSIONS), + .h.paramSize = swap32(sizeof(cmd_rsp.update_c) + max_bytes), + .h.ordinal = swap32(TPM2_PCR_SequenceUpdate), + .sequenceHandle = swap32(seq_handle), + .sessionHdrSize = swap32(sizeof(struct tpm2_session_header)), + .session.handle = swap32(TPM_RS_PW), + .dataSize = swap16(max_bytes), + }; + + memcpy(cmd_rsp.update_c.data, buf, max_bytes); + + o_size = sizeof(cmd_rsp); + send_cmd(loc, cmd_rsp.b, swap32(cmd_rsp.c.paramSize), &o_size); + + if ( cmd_rsp.r.tag == swap16(TPM_ST_NO_SESSIONS) && + cmd_rsp.r.paramSize == swap32(10) ) { + rc = swap32(cmd_rsp.r.returnCode); + if ( rc != 0 ) + goto error; + } + + size -= max_bytes; + buf += max_bytes; + } + + cmd_rsp.finish_c = (struct tpm2_sequence_complete_cmd) { + .h.tag = swap16(TPM_ST_SESSIONS), + .h.paramSize = swap32(sizeof(cmd_rsp.finish_c) + size), + .h.ordinal = swap32(TPM2_PCR_EventSequenceComplete), + .pcrHandle = swap32(HR_PCR + pcr), + .sequenceHandle = swap32(seq_handle), + .sessionHdrSize = swap32(sizeof(struct tpm2_session_header)*2), + .pcrSession.handle = swap32(TPM_RS_PW), + .sequenceSession.handle = swap32(TPM_RS_PW), + .dataSize = swap16(size), + }; + + memcpy(cmd_rsp.finish_c.data, buf, size); + + o_size = sizeof(cmd_rsp); + send_cmd(loc, cmd_rsp.b, swap32(cmd_rsp.c.paramSize), &o_size); + + if ( cmd_rsp.r.tag == swap16(TPM_ST_NO_SESSIONS) && + cmd_rsp.r.paramSize == swap32(10) ) { + rc = swap32(cmd_rsp.r.returnCode); + if ( rc != 0 ) + goto error; + } + + p = cmd_rsp.finish_r.hashes; + for ( i = 0; i < swap32(cmd_rsp.finish_r.hashCount); ++i ) { + unsigned j; + uint16_t hash_type; + + hash_type = swap16(*(uint16_t *)p); + p += sizeof(uint16_t); + + for ( j = 0; j < log_hashes->count; ++j ) { + struct tpm2_log_hash *hash = &log_hashes->hashes[j]; + if ( hash->alg == hash_type ) { + memcpy(hash->data, p, hash->size); + p += hash->size; + break; + } + } + + if ( j == log_hashes->count ) { + /* Can't continue parsing without knowing hash size. */ + break; + } + } + + rc = 0; + +error: + relinquish_locality(loc); + return rc; +} + +#else + +union tpm2_cmd_rsp { + /* Enough space for multiple hashes. */ + uint8_t b[sizeof(struct tpm2_extend_cmd) + 1024]; + struct tpm_cmd_hdr c; + struct tpm_rsp_hdr r; + struct tpm2_extend_cmd extend_c; + struct tpm2_extend_rsp extend_r; +}; + +static uint32_t tpm20_pcr_extend(unsigned loc, uint32_t pcr_handle, + const struct tpm2_log_hashes *log_hashes) +{ + union tpm2_cmd_rsp cmd_rsp; + unsigned o_size; + unsigned i; + uint8_t *p; + + cmd_rsp.extend_c = (struct tpm2_extend_cmd) { + .h.tag = swap16(TPM_ST_SESSIONS), + .h.ordinal = swap32(TPM2_PCR_Extend), + .pcrHandle = swap32(pcr_handle), + .sessionHdrSize = swap32(sizeof(struct tpm2_session_header)), + .pcrSession.handle = swap32(TPM_RS_PW), + .hashCount = swap32(log_hashes->count), + }; + + p = cmd_rsp.extend_c.hashes; + for ( i = 0; i < log_hashes->count; ++i ) { + const struct tpm2_log_hash *hash = &log_hashes->hashes[i]; + + if ( p + sizeof(uint16_t) + hash->size > &cmd_rsp.b[sizeof(cmd_rsp)] ) { + printk(XENLOG_ERR "Hit TPM message size implementation limit: %ld\n", + sizeof(cmd_rsp)); + return -1; + } + + *(uint16_t *)p = swap16(hash->alg); + p += sizeof(uint16_t); + + memcpy(p, hash->data, hash->size); + p += hash->size; + } + + /* Fill in command size (size of the whole buffer). */ + cmd_rsp.extend_c.h.paramSize = swap32(sizeof(cmd_rsp.extend_c) + + (p - cmd_rsp.extend_c.hashes)), + + o_size = sizeof(cmd_rsp); + send_cmd(loc, cmd_rsp.b, swap32(cmd_rsp.c.paramSize), &o_size); + + return swap32(cmd_rsp.r.returnCode); +} + +static bool tpm_supports_hash(unsigned loc, const struct tpm2_log_hash *hash) +{ + uint32_t rc; + struct tpm2_log_hashes hashes = { + .count = 1, + .hashes[0] = *hash, + }; + + /* This is a valid way of checking hash support, using it to not implement + * TPM2_GetCapability(). */ + rc = tpm20_pcr_extend(loc, /*pcr_handle=*/TPM_RH_NULL, &hashes); + + return rc == 0; +} + +static uint32_t tpm2_hash_extend(unsigned loc, uint8_t *buf, unsigned size, + unsigned pcr, + const struct tpm2_log_hashes *log_hashes) +{ + uint32_t rc; + unsigned i; + struct tpm2_log_hashes supported_hashes = {0}; + + request_locality(loc); + + for ( i = 0; i < log_hashes->count; ++i ) { + const struct tpm2_log_hash *hash = &log_hashes->hashes[i]; + if ( !tpm_supports_hash(loc, hash) ) { + printk(XENLOG_WARNING "Skipped hash unsupported by TPM: %d\n", + hash->alg); + continue; + } + + if ( hash->alg == TPM_ALG_SHA1 ) { + sha1_hash(buf, size, hash->data); + } else if ( hash->alg == TPM_ALG_SHA256 ) { + sha256_hash(buf, size, hash->data); + } else { + /* This is called "OneDigest" in TXT Software Development Guide. */ + memset(hash->data, 0, size); + hash->data[0] = 1; + } + + if ( supported_hashes.count == MAX_HASH_COUNT ) { + printk(XENLOG_ERR "Hit hash count implementation limit: %d\n", + MAX_HASH_COUNT); + return -1; + } + + supported_hashes.hashes[supported_hashes.count] = *hash; + ++supported_hashes.count; + } + + rc = tpm20_pcr_extend(loc, HR_PCR + pcr, &supported_hashes); + relinquish_locality(loc); + + return rc; +} + +#endif /* __EARLY_TPM__ */ + +/************************** end of TPM2.0 specific ****************************/ + void tpm_hash_extend(unsigned loc, unsigned pcr, uint8_t *buf, unsigned size, uint32_t type, uint8_t *log_data, unsigned log_data_size) { @@ -419,6 +813,34 @@ void tpm_hash_extend(unsigned loc, unsigned pcr, uint8_t *buf, unsigned size, if ( !tpm12_hash_extend(loc, buf, size, pcr, entry_digest) ) { #ifndef __EARLY_TPM__ printk(XENLOG_ERR "Extending PCR%u failed\n", pcr); +#endif + } + } else { + uint8_t sha1_digest[SHA1_DIGEST_SIZE]; + uint8_t sha256_digest[SHA256_DIGEST_SIZE]; + uint32_t rc; + + struct tpm2_log_hashes log_hashes = { + .count = 2, + .hashes = { + { + .alg = TPM_ALG_SHA1, + .size = SHA1_DIGEST_SIZE, + .data = sha1_digest, + }, + { + .alg = TPM_ALG_SHA256, + .size = SHA256_DIGEST_SIZE, + .data = sha256_digest, + }, + }, + }; + + rc = tpm2_hash_extend(loc, buf, size, pcr, &log_hashes); + if ( rc != 0 ) { +#ifndef __EARLY_TPM__ + printk(XENLOG_ERR "Extending PCR%u failed with TPM error: 0x%08x\n", + pcr, rc); #endif } } From d43c355ebd8832425d8fcd2482b1d53e80f94b68 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Sat, 1 Jul 2023 00:41:35 +0300 Subject: [PATCH 29/46] x86/tpm.c: implement event log for TPM2.0 Signed-off-by: Sergii Dmytruk --- xen/arch/x86/include/asm/intel_txt.h | 33 ++++++ xen/arch/x86/tpm.c | 163 +++++++++++++++++++++++---- 2 files changed, 172 insertions(+), 24 deletions(-) diff --git a/xen/arch/x86/include/asm/intel_txt.h b/xen/arch/x86/include/asm/intel_txt.h index be428402b1..c14e4c2188 100644 --- a/xen/arch/x86/include/asm/intel_txt.h +++ b/xen/arch/x86/include/asm/intel_txt.h @@ -197,6 +197,39 @@ struct txt_sinit_mle_data { /* Ext Data Elements */ } __packed; +/* Types of extended data. */ +#define TXT_HEAP_EXTDATA_TYPE_END 0 +#define TXT_HEAP_EXTDATA_TYPE_BIOS_SPEC_VER 1 +#define TXT_HEAP_EXTDATA_TYPE_ACM 2 +#define TXT_HEAP_EXTDATA_TYPE_STM 3 +#define TXT_HEAP_EXTDATA_TYPE_CUSTOM 4 +#define TXT_HEAP_EXTDATA_TYPE_MADT 6 +#define TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1 8 +#define TXT_HEAP_EXTDATA_TYPE_MCFG 9 +#define TXT_HEAP_EXTDATA_TYPE_TPR_REQ 13 +#define TXT_HEAP_EXTDATA_TYPE_DTPR 14 +#define TXT_HEAP_EXTDATA_TYPE_CEDT 15 + +/* + * Self-describing data structure that is used for extensions to TXT heap + * tables. + */ +struct txt_ext_data_element { + uint32_t type; /* One of TXT_HEAP_EXTDATA_TYPE_*. */ + uint32_t size; + uint8_t data[0]; /* size bytes. */ +} __packed; + +/* + * Extended data describing TPM 2.0 log. + */ +struct heap_event_log_pointer_element2_1 { + uint64_t physical_address; + uint32_t allocated_event_container_size; + uint32_t first_record_offset; + uint32_t next_record_offset; +} __packed; + /* * Functions to extract data from the Intel TXT Heap Memory. The layout * of the heap is as follows: diff --git a/xen/arch/x86/tpm.c b/xen/arch/x86/tpm.c index 5bfba8a1f9..90056cda8e 100644 --- a/xen/arch/x86/tpm.c +++ b/xen/arch/x86/tpm.c @@ -538,6 +538,44 @@ struct tpm2_log_hashes { struct tpm2_log_hash hashes[MAX_HASH_COUNT]; }; +struct tpm2_pcr_event_header { + uint32_t pcrIndex; + uint32_t eventType; + uint32_t digestCount; + uint8_t digests[0]; + /* + * Each hash is represented as: + * struct { + * uint16_t hashAlg; + * uint8_t hash[size of hashAlg]; + * }; + */ + /* uint32_t eventSize; */ + /* uint8_t event[0]; */ +} __packed; + +struct tpm2_digest_sizes { + uint16_t algId; + uint16_t digestSize; +} __packed; + +struct tpm2_spec_id_event { + uint32_t pcrIndex; + uint32_t eventType; + uint8_t digest[20]; + uint32_t eventSize; + uint8_t signature[16]; + uint32_t platformClass; + uint8_t specVersionMinor; + uint8_t specVersionMajor; + uint8_t specErrata; + uint8_t uintnSize; + uint32_t digestCount; + struct tpm2_digest_sizes digestSizes[0]; /* variable number of members */ + /* uint8_t vendorInfoSize; */ + /* uint8_t vendorInfo[vendorInfoSize]; */ +} __packed; + #ifdef __EARLY_TPM__ union tpm2_cmd_rsp { @@ -758,15 +796,12 @@ static uint32_t tpm2_hash_extend(unsigned loc, uint8_t *buf, unsigned size, continue; } - if ( hash->alg == TPM_ALG_SHA1 ) { + if ( hash->alg == TPM_ALG_SHA1 ) sha1_hash(buf, size, hash->data); - } else if ( hash->alg == TPM_ALG_SHA256 ) { + else if ( hash->alg == TPM_ALG_SHA256 ) sha256_hash(buf, size, hash->data); - } else { - /* This is called "OneDigest" in TXT Software Development Guide. */ - memset(hash->data, 0, size); - hash->data[0] = 1; - } + else + /* create_log_event20() took care of initializing the digest. */; if ( supported_hashes.count == MAX_HASH_COUNT ) { printk(XENLOG_ERR "Hit hash count implementation limit: %d\n", @@ -786,6 +821,99 @@ static uint32_t tpm2_hash_extend(unsigned loc, uint8_t *buf, unsigned size, #endif /* __EARLY_TPM__ */ +static struct heap_event_log_pointer_element2_1 *find_evt_log_ext_data(void) +{ + struct txt_os_sinit_data *os_sinit; + struct txt_ext_data_element *ext_data; + + os_sinit = txt_os_sinit_data_start(__va(read_txt_reg(TXTCR_HEAP_BASE))); + ext_data = (void *)((uint8_t *)os_sinit + sizeof(*os_sinit)); + + /* + * Find TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1 which is necessary to + * know where to put the next entry. + */ + while ( ext_data->type != TXT_HEAP_EXTDATA_TYPE_END ) { + if ( ext_data->type == TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1 ) + break; + ext_data = (void *)&ext_data->data[ext_data->size]; + } + + if ( ext_data->type == TXT_HEAP_EXTDATA_TYPE_END ) + return NULL; + + return (void *)&ext_data->data[0]; +} + +static struct tpm2_log_hashes +create_log_event20(struct tpm2_spec_id_event *evt_log, uint32_t evt_log_size, + uint32_t pcr, uint32_t type, uint8_t *data, + unsigned data_size) +{ + struct tpm2_log_hashes log_hashes = {0}; + + struct heap_event_log_pointer_element2_1 *log_ext_data; + struct tpm2_pcr_event_header *new_entry; + uint32_t entry_size; + unsigned i; + uint8_t *p; + + log_ext_data = find_evt_log_ext_data(); + if ( log_ext_data == NULL ) + return log_hashes; + + entry_size = sizeof(*new_entry); + for ( i = 0; i < evt_log->digestCount; ++i ) { + entry_size += sizeof(uint16_t); /* hash type */ + entry_size += evt_log->digestSizes[i].digestSize; + } + entry_size += sizeof(uint32_t); /* data size field */ + entry_size += data_size; + + /* + * Check if there is enough space left for new entry. + * Note: it is possible to introduce a gap in event log if entry with big + * data_size is followed by another entry with smaller data. Maybe we should + * cap the event log size in such case? + */ + if ( log_ext_data->next_record_offset + entry_size > evt_log_size ) + return log_hashes; + + new_entry = (void *)((uint8_t *)evt_log + log_ext_data->next_record_offset); + log_ext_data->next_record_offset += entry_size; + + new_entry->pcrIndex = pcr; + new_entry->eventType = type; + new_entry->digestCount = evt_log->digestCount; + + p = &new_entry->digests[0]; + for ( i = 0; i < evt_log->digestCount; ++i ) { + uint16_t alg = evt_log->digestSizes[i].algId; + uint16_t size = evt_log->digestSizes[i].digestSize; + + *(uint16_t *)p = alg; + p += sizeof(uint16_t); + + log_hashes.hashes[i].alg = alg; + log_hashes.hashes[i].size = size; + log_hashes.hashes[i].data = p; + p += size; + + /* This is called "OneDigest" in TXT Software Development Guide. */ + memset(log_hashes.hashes[i].data, 0, size); + log_hashes.hashes[i].data[0] = 1; + } + log_hashes.count = evt_log->digestCount; + + *(uint32_t *)p = data_size; + p += sizeof(uint32_t); + + if ( data && data_size > 0 ) + memcpy(p, data, data_size); + + return log_hashes; +} + /************************** end of TPM2.0 specific ****************************/ void tpm_hash_extend(unsigned loc, unsigned pcr, uint8_t *buf, unsigned size, @@ -816,25 +944,12 @@ void tpm_hash_extend(unsigned loc, unsigned pcr, uint8_t *buf, unsigned size, #endif } } else { - uint8_t sha1_digest[SHA1_DIGEST_SIZE]; - uint8_t sha256_digest[SHA256_DIGEST_SIZE]; uint32_t rc; - struct tpm2_log_hashes log_hashes = { - .count = 2, - .hashes = { - { - .alg = TPM_ALG_SHA1, - .size = SHA1_DIGEST_SIZE, - .data = sha1_digest, - }, - { - .alg = TPM_ALG_SHA256, - .size = SHA256_DIGEST_SIZE, - .data = sha256_digest, - }, - }, - }; + struct tpm2_spec_id_event *evt_log = evt_log_addr; + struct tpm2_log_hashes log_hashes = + create_log_event20(evt_log, evt_log_size, pcr, type, log_data, + log_data_size); rc = tpm2_hash_extend(loc, buf, size, pcr, &log_hashes); if ( rc != 0 ) { From f7d9b1f86bcbbf18ad0a8650b96e9017e919d7d8 Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Wed, 16 Nov 2022 15:03:07 +0100 Subject: [PATCH 30/46] x86/boot: choose AP stack based on APIC ID This is made as the first step of making parallel AP bring-up possible. It should be enough for pre-C code. Parallel AP bring-up is necessary because TXT by design releases all APs at once. In addition to that it reduces number of IPIs (and more importantly, delays between them) required to start all logical processors. This results in significant reduction of boot time, even when DRTM is not used, with performance gain growing with the number of logical CPUs. Signed-off-by: Krystian Hebel Signed-off-by: Sergii Dmytruk --- xen/arch/x86/boot/head.S | 1 + xen/arch/x86/boot/trampoline.S | 21 +++++++++++++++++++++ xen/arch/x86/boot/x86_64.S | 28 +++++++++++++++++++++++++++- xen/arch/x86/include/asm/apicdef.h | 4 ++++ xen/arch/x86/include/asm/msr-index.h | 3 +++ xen/arch/x86/setup.c | 7 +++++++ 6 files changed, 63 insertions(+), 1 deletion(-) diff --git a/xen/arch/x86/boot/head.S b/xen/arch/x86/boot/head.S index 2a60bb0b8d..98cfa3f92f 100644 --- a/xen/arch/x86/boot/head.S +++ b/xen/arch/x86/boot/head.S @@ -8,6 +8,7 @@ #include #include #include +#include #include #include diff --git a/xen/arch/x86/boot/trampoline.S b/xen/arch/x86/boot/trampoline.S index 924bda37c1..3da2f10955 100644 --- a/xen/arch/x86/boot/trampoline.S +++ b/xen/arch/x86/boot/trampoline.S @@ -72,6 +72,27 @@ trampoline_protmode_entry: mov $X86_CR4_PAE,%ecx mov %ecx,%cr4 + /* + * Get APIC ID while we're in non-paged mode. Start by checking if + * x2APIC is enabled. + */ + mov $MSR_APIC_BASE, %ecx + rdmsr + test $APIC_BASE_EXTD, %eax + jnz .Lx2apic + + /* Not x2APIC, read from MMIO */ + and $APIC_BASE_ADDR_MASK, %eax + mov APIC_ID(%eax), %esp + shr $24, %esp + jmp 1f + +.Lx2apic: + mov $(MSR_X2APIC_FIRST + (APIC_ID >> MSR_X2APIC_SHIFT)), %ecx + rdmsr + mov %eax, %esp +1: + /* Load pagetable base register. */ mov $sym_offs(idle_pg_table),%eax add bootsym_rel(trampoline_xen_phys_start,4,%eax) diff --git a/xen/arch/x86/boot/x86_64.S b/xen/arch/x86/boot/x86_64.S index 26b9d1c2df..a86dc50f10 100644 --- a/xen/arch/x86/boot/x86_64.S +++ b/xen/arch/x86/boot/x86_64.S @@ -15,7 +15,33 @@ ENTRY(__high_start) mov $XEN_MINIMAL_CR4,%rcx mov %rcx,%cr4 - mov stack_start(%rip),%rsp + test %ebx,%ebx + cmovz stack_start(%rip), %rsp + jz .L_stack_set + + /* APs only: get stack base from APIC ID saved in %esp. */ + mov $-1, %rax + lea x86_cpu_to_apicid(%rip), %rcx +1: + add $1, %rax + cmp $NR_CPUS, %eax + jb 2f + hlt +2: + cmp %esp, (%rcx, %rax, 4) + jne 1b + + /* %eax is now Xen CPU index. */ + lea stack_base(%rip), %rcx + mov (%rcx, %rax, 8), %rsp + + test %rsp,%rsp + jnz 1f + hlt +1: + add $(STACK_SIZE - CPUINFO_sizeof), %rsp + +.L_stack_set: /* Reset EFLAGS (subsumes CLI and CLD). */ pushq $0 diff --git a/xen/arch/x86/include/asm/apicdef.h b/xen/arch/x86/include/asm/apicdef.h index 49e29ec801..f687d30998 100644 --- a/xen/arch/x86/include/asm/apicdef.h +++ b/xen/arch/x86/include/asm/apicdef.h @@ -119,6 +119,10 @@ #define MAX_IO_APICS 128 +#ifndef __ASSEMBLY__ + extern bool x2apic_enabled; +#endif /* !__ASSEMBLY__ */ + #endif diff --git a/xen/arch/x86/include/asm/msr-index.h b/xen/arch/x86/include/asm/msr-index.h index 9cdb5b2625..5a153a6b84 100644 --- a/xen/arch/x86/include/asm/msr-index.h +++ b/xen/arch/x86/include/asm/msr-index.h @@ -169,6 +169,9 @@ #define MSR_X2APIC_FIRST 0x00000800 #define MSR_X2APIC_LAST 0x000008ff +/* MSR offset can be obtained by shifting MMIO offset this number of bits to the right. */ +#define MSR_X2APIC_SHIFT 4 + #define MSR_X2APIC_TPR 0x00000808 #define MSR_X2APIC_PPR 0x0000080a #define MSR_X2APIC_EOI 0x0000080b diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index f7af7b981f..378232f3b7 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -2057,6 +2057,7 @@ void asmlinkage __init noreturn __start_xen(void) */ if ( !pv_shim ) { + /* Separate loop to make parallel AP bringup possible. */ for_each_present_cpu ( i ) { /* Set up cpu_to_node[]. */ @@ -2064,6 +2065,12 @@ void asmlinkage __init noreturn __start_xen(void) /* Set up node_to_cpumask based on cpu_to_node[]. */ numa_add_cpu(i); + if ( stack_base[i] == NULL ) + stack_base[i] = cpu_alloc_stack(i); + } + + for_each_present_cpu ( i ) + { if ( (park_offline_cpus || num_online_cpus() < max_cpus) && !cpu_online(i) ) { From 44ebc119b850ab059ddd19bc78cf96a6530483df Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Wed, 16 Nov 2022 15:06:18 +0100 Subject: [PATCH 31/46] x86/smpboot.c: TXT AP bringup On Intel TXT, APs are started in one of two ways, depending on ACM which reports it in its information table. In both cases, all APs are started simultaneously after BSP requests them to do so. Two possible ways are: - GETSEC[WAKEUP] instruction, - MONITOR address. GETSEC[WAKEUP] requires versions >= 7 of SINIT to MLE Data, but there is no clear mapping of that version with regard to processor family and it's not known which CPUs actually use it. It could have been designed for TXT support on CPUs that lack MONITOR/MWAIT, because GETSEC[WAKEUP] seems to be more complicated, in software and hardware alike. This patch implements only MONITOR approach, GETSEC[WAKEUP] support will be added later once more details and means of testing are available and if there is a practical need for it. With this patch, every AP goes through assembly part, and only when in start_secondary() in C they re-enter MONITOR/MWAIT iff they are not the AP that was asked to boot. The same address is reused for simplicity, and on next wakeup call APs don't have to go through assembly part again (GDT, paging, stack setting). Signed-off-by: Krystian Hebel Signed-off-by: Sergii Dmytruk --- xen/arch/x86/boot/trampoline.S | 19 +++++++++- xen/arch/x86/include/asm/intel_txt.h | 6 +++ xen/arch/x86/include/asm/processor.h | 1 + xen/arch/x86/smpboot.c | 56 ++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 1 deletion(-) diff --git a/xen/arch/x86/boot/trampoline.S b/xen/arch/x86/boot/trampoline.S index 3da2f10955..3fd6d1bf2c 100644 --- a/xen/arch/x86/boot/trampoline.S +++ b/xen/arch/x86/boot/trampoline.S @@ -59,6 +59,16 @@ GLOBAL(trampoline_realmode_entry) ljmpl $BOOT_CS32,$bootsym_rel(trampoline_protmode_entry,6) .code32 +GLOBAL(txt_ap_entry) + /* + * APs enter here in protected mode without paging. GDT is set in JOIN + * structure, it points to trampoline_gdt. Interrupts are disabled by + * TXT (including NMI and SMI), so IDT doesn't matter at this point. + * The only missing point is telling that we are AP by saving non-zero + * value in EBX. + */ + mov $1, %ebx + trampoline_protmode_entry: /* Set up a few descriptors: on entry only CS is guaranteed good. */ mov $BOOT_DS,%eax @@ -144,7 +154,7 @@ start64: .word 0 idt_48: .word 0, 0, 0 # base = limit = 0 -trampoline_gdt: +GLOBAL(trampoline_gdt) .word 0 /* 0x0000: unused (reused for GDTR) */ gdt_48: .word .Ltrampoline_gdt_end - trampoline_gdt - 1 @@ -155,6 +165,13 @@ gdt_48: .quad 0x00cf93000000ffff /* 0x0018: ring 0 data */ .quad 0x00009b000000ffff /* 0x0020: real-mode code @ BOOT_TRAMPOLINE */ .quad 0x000093000000ffff /* 0x0028: real-mode data @ BOOT_TRAMPOLINE */ + /* + * Intel TXT requires these two in exact order. This isn't compatible + * with order required by syscall, so we have duplicated entries... + * If order ever changes, update selector numbers in asm/intel_txt.h. + */ + .quad 0x00cf9b000000ffff /* 0x0030: ring 0 code, 32-bit mode */ + .quad 0x00cf93000000ffff /* 0x0038: ring 0 data */ .Ltrampoline_gdt_end: /* Relocations for trampoline Real Mode segments. */ diff --git a/xen/arch/x86/include/asm/intel_txt.h b/xen/arch/x86/include/asm/intel_txt.h index c14e4c2188..d33469166f 100644 --- a/xen/arch/x86/include/asm/intel_txt.h +++ b/xen/arch/x86/include/asm/intel_txt.h @@ -75,10 +75,16 @@ #define SLAUNCH_BOOTLOADER_MAGIC 0x4c534254 +#define TXT_AP_BOOT_CS 0x0030 +#define TXT_AP_BOOT_DS 0x0038 + #ifndef __ASSEMBLY__ extern bool slaunch_active; +extern char txt_ap_entry[]; +extern uint32_t trampoline_gdt[]; + /* We need to differentiate between pre- and post paging enabled. */ #ifdef __XEN_CONFIG_H__ #include diff --git a/xen/arch/x86/include/asm/processor.h b/xen/arch/x86/include/asm/processor.h index 8776512122..39fcd42d91 100644 --- a/xen/arch/x86/include/asm/processor.h +++ b/xen/arch/x86/include/asm/processor.h @@ -520,6 +520,7 @@ void set_in_mcu_opt_ctrl(uint32_t mask, uint32_t val); enum ap_boot_method { AP_BOOT_NORMAL, AP_BOOT_SKINIT, + AP_BOOT_TXT, }; extern enum ap_boot_method ap_boot_method; diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c index 79a79c54c3..fa1c2ecacf 100644 --- a/xen/arch/x86/smpboot.c +++ b/xen/arch/x86/smpboot.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -323,6 +324,29 @@ void asmlinkage start_secondary(void *unused) */ unsigned int cpu = booting_cpu; + if ( ap_boot_method == AP_BOOT_TXT ) { + uint64_t misc_enable; + uint32_t my_apicid; + struct txt_sinit_mle_data *sinit_mle = + txt_sinit_mle_data_start(__va(read_txt_reg(TXTCR_HEAP_BASE))); + + /* TXT released us with MONITOR disabled in IA32_MISC_ENABLE. */ + rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable); + wrmsrl(MSR_IA32_MISC_ENABLE, + misc_enable | MSR_IA32_MISC_ENABLE_MONITOR_ENABLE); + + /* get_apic_id() reads from x2APIC if it thinks it is enabled. */ + x2apic_ap_setup(); + my_apicid = get_apic_id(); + + while ( my_apicid != x86_cpu_to_apicid[cpu] ) { + asm volatile ("monitor; xor %0,%0; mwait" + :: "a"(__va(sinit_mle->rlp_wakeup_addr)), "c"(0), + "d"(0) : "memory"); + cpu = booting_cpu; + } + } + /* Critical region without IDT or TSS. Any fault is deadly! */ set_current(idle_vcpu[cpu]); @@ -419,6 +443,28 @@ void asmlinkage start_secondary(void *unused) startup_cpu_idle_loop(); } +static int wake_aps_in_txt(void) +{ + struct txt_sinit_mle_data *sinit_mle = + txt_sinit_mle_data_start(__va(read_txt_reg(TXTCR_HEAP_BASE))); + uint32_t *wakeup_addr = __va(sinit_mle->rlp_wakeup_addr); + + uint32_t join[4] = { + trampoline_gdt[1], /* GDT limit */ + bootsym_phys(trampoline_gdt), /* GDT base */ + TXT_AP_BOOT_CS, /* CS selector, DS = CS+8 */ + bootsym_phys(txt_ap_entry) /* EIP */ + }; + + write_txt_reg(TXTCR_MLE_JOIN, __pa(join)); + + smp_mb(); + + *wakeup_addr = 1; + + return 0; +} + static int wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip) { unsigned long send_status = 0, accept_status = 0; @@ -441,6 +487,9 @@ static int wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip) if ( tboot_in_measured_env() && !tboot_wake_ap(phys_apicid, start_eip) ) return 0; + if ( ap_boot_method == AP_BOOT_TXT ) + return wake_aps_in_txt(); + /* * Be paranoid about clearing APIC errors. */ @@ -1148,6 +1197,13 @@ static struct notifier_block cpu_smpboot_nfb = { void __init smp_prepare_cpus(void) { + /* + * If the platform is performing a Secure Launch via TXT, secondary + * CPUs (APs) will need to be woken up in a TXT-specific way. + */ + if ( slaunch_active && boot_cpu_data.x86_vendor == X86_VENDOR_INTEL ) + ap_boot_method = AP_BOOT_TXT; + register_cpu_notifier(&cpu_smpboot_nfb); mtrr_aps_sync_begin(); From 90abc7f3cfde40ef937b93a3496f1af6c593fafa Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Thu, 1 Jun 2023 16:05:18 +0200 Subject: [PATCH 32/46] arch/x86: don't access x86_cpu_to_apicid[] directly, use cpu_physical_id(cpu) This is done in preparation to move data from x86_cpu_to_apicid[] elsewhere. Signed-off-by: Krystian Hebel --- xen/arch/x86/acpi/cpu_idle.c | 4 ++-- xen/arch/x86/acpi/lib.c | 2 +- xen/arch/x86/apic.c | 2 +- xen/arch/x86/cpu/mwait-idle.c | 4 ++-- xen/arch/x86/domain.c | 2 +- xen/arch/x86/mpparse.c | 6 +++--- xen/arch/x86/numa.c | 2 +- xen/arch/x86/platform_hypercall.c | 2 +- xen/arch/x86/setup.c | 14 +++++++------- xen/arch/x86/smpboot.c | 6 +++--- xen/arch/x86/spec_ctrl.c | 2 +- xen/arch/x86/sysctl.c | 2 +- 12 files changed, 24 insertions(+), 24 deletions(-) diff --git a/xen/arch/x86/acpi/cpu_idle.c b/xen/arch/x86/acpi/cpu_idle.c index 876317fad0..46adda8755 100644 --- a/xen/arch/x86/acpi/cpu_idle.c +++ b/xen/arch/x86/acpi/cpu_idle.c @@ -1244,7 +1244,7 @@ int get_cpu_id(u32 acpi_id) for ( i = 0; i < nr_cpu_ids; i++ ) { - if ( apic_id == x86_cpu_to_apicid[i] ) + if ( apic_id == cpu_physical_id(i) ) return i; } @@ -1350,7 +1350,7 @@ long set_cx_pminfo(uint32_t acpi_id, struct xen_processor_power *power) if ( !cpu_online(cpu_id) ) { - uint32_t apic_id = x86_cpu_to_apicid[cpu_id]; + uint32_t apic_id = cpu_physical_id(cpu_id); /* * If we've just learned of more available C states, wake the CPU if diff --git a/xen/arch/x86/acpi/lib.c b/xen/arch/x86/acpi/lib.c index 51cb082ca0..87a1f38f3f 100644 --- a/xen/arch/x86/acpi/lib.c +++ b/xen/arch/x86/acpi/lib.c @@ -91,7 +91,7 @@ unsigned int acpi_get_processor_id(unsigned int cpu) { unsigned int acpiid, apicid; - if ((apicid = x86_cpu_to_apicid[cpu]) == BAD_APICID) + if ((apicid = cpu_physical_id(cpu)) == BAD_APICID) return INVALID_ACPIID; for (acpiid = 0; acpiid < ARRAY_SIZE(x86_acpiid_to_apicid); acpiid++) diff --git a/xen/arch/x86/apic.c b/xen/arch/x86/apic.c index bb86a1c161..feae06f57c 100644 --- a/xen/arch/x86/apic.c +++ b/xen/arch/x86/apic.c @@ -948,7 +948,7 @@ void __init init_apic_mappings(void) */ if (boot_cpu_physical_apicid == -1U) boot_cpu_physical_apicid = get_apic_id(); - x86_cpu_to_apicid[0] = get_apic_id(); + cpu_physical_id(0) = get_apic_id(); ioapic_init(); } diff --git a/xen/arch/x86/cpu/mwait-idle.c b/xen/arch/x86/cpu/mwait-idle.c index 9c16cc166a..ff5ce2ec56 100644 --- a/xen/arch/x86/cpu/mwait-idle.c +++ b/xen/arch/x86/cpu/mwait-idle.c @@ -1180,8 +1180,8 @@ static void __init ivt_idle_state_table_update(void) unsigned int cpu, max_apicid = boot_cpu_physical_apicid; for_each_present_cpu(cpu) - if (max_apicid < x86_cpu_to_apicid[cpu]) - max_apicid = x86_cpu_to_apicid[cpu]; + if (max_apicid < cpu_physical_id(cpu)) + max_apicid = cpu_physical_id(cpu); switch (apicid_to_socket(max_apicid)) { case 0: case 1: /* 1 and 2 socket systems use default ivt_cstates */ diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 78a13e6812..c7142d25e8 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -1636,7 +1636,7 @@ long do_vcpu_op(int cmd, unsigned int vcpuid, XEN_GUEST_HANDLE_PARAM(void) arg) break; cpu_id.phys_id = - (uint64_t)x86_cpu_to_apicid[v->vcpu_id] | + (uint64_t)cpu_physical_id(v->vcpu_id) | ((uint64_t)acpi_get_processor_id(v->vcpu_id) << 32); rc = -EFAULT; diff --git a/xen/arch/x86/mpparse.c b/xen/arch/x86/mpparse.c index e74a714f50..05efc4cc0d 100644 --- a/xen/arch/x86/mpparse.c +++ b/xen/arch/x86/mpparse.c @@ -186,7 +186,7 @@ static int MP_processor_info_x(struct mpc_config_processor *m, " Processor with apicid %i ignored\n", apicid); return cpu; } - x86_cpu_to_apicid[cpu] = apicid; + cpu_physical_id(cpu) = apicid; cpumask_set_cpu(cpu, &cpu_present_map); } @@ -829,12 +829,12 @@ void mp_unregister_lapic(uint32_t apic_id, uint32_t cpu) if (!cpu || (apic_id == boot_cpu_physical_apicid)) return; - if (x86_cpu_to_apicid[cpu] != apic_id) + if (cpu_physical_id(cpu) != apic_id) return; physid_clear(apic_id, phys_cpu_present_map); - x86_cpu_to_apicid[cpu] = BAD_APICID; + cpu_physical_id(cpu) = BAD_APICID; cpumask_clear_cpu(cpu, &cpu_present_map); } diff --git a/xen/arch/x86/numa.c b/xen/arch/x86/numa.c index ae3cc7a8d0..f0ec500be2 100644 --- a/xen/arch/x86/numa.c +++ b/xen/arch/x86/numa.c @@ -70,7 +70,7 @@ void __init init_cpu_to_node(void) for ( i = 0; i < nr_cpu_ids; i++ ) { - u32 apicid = x86_cpu_to_apicid[i]; + u32 apicid = cpu_physical_id(i); if ( apicid == BAD_APICID ) continue; node = apicid < MAX_LOCAL_APIC ? apicid_to_node[apicid] : NUMA_NO_NODE; diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c index 67f851237d..7dabf85330 100644 --- a/xen/arch/x86/platform_hypercall.c +++ b/xen/arch/x86/platform_hypercall.c @@ -597,7 +597,7 @@ ret_t do_platform_op( } else { - g_info->apic_id = x86_cpu_to_apicid[g_info->xen_cpuid]; + g_info->apic_id = cpu_physical_id(g_info->xen_cpuid); g_info->acpi_id = acpi_get_processor_id(g_info->xen_cpuid); ASSERT(g_info->apic_id != BAD_APICID); g_info->flags = 0; diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 378232f3b7..8eab8adecf 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -396,7 +396,7 @@ static void __init init_idle_domain(void) void srat_detect_node(int cpu) { nodeid_t node; - u32 apicid = x86_cpu_to_apicid[cpu]; + u32 apicid = cpu_physical_id(cpu); node = apicid < MAX_LOCAL_APIC ? apicid_to_node[apicid] : NUMA_NO_NODE; if ( node == NUMA_NO_NODE ) @@ -423,7 +423,7 @@ static void __init normalise_cpu_order(void) for_each_present_cpu ( i ) { - apicid = x86_cpu_to_apicid[i]; + apicid = cpu_physical_id(i); min_diff = min_cpu = ~0u; /* @@ -434,12 +434,12 @@ static void __init normalise_cpu_order(void) j < nr_cpu_ids; j = cpumask_next(j, &cpu_present_map) ) { - diff = x86_cpu_to_apicid[j] ^ apicid; + diff = cpu_physical_id(j) ^ apicid; while ( diff & (diff-1) ) diff &= diff-1; if ( (diff < min_diff) || ((diff == min_diff) && - (x86_cpu_to_apicid[j] < x86_cpu_to_apicid[min_cpu])) ) + (cpu_physical_id(j) < cpu_physical_id(min_cpu))) ) { min_diff = diff; min_cpu = j; @@ -455,9 +455,9 @@ static void __init normalise_cpu_order(void) /* Switch the best-matching CPU with the next CPU in logical order. */ j = cpumask_next(i, &cpu_present_map); - apicid = x86_cpu_to_apicid[min_cpu]; - x86_cpu_to_apicid[min_cpu] = x86_cpu_to_apicid[j]; - x86_cpu_to_apicid[j] = apicid; + apicid = cpu_physical_id(min_cpu); + cpu_physical_id(min_cpu) = cpu_physical_id(j); + cpu_physical_id(j) = apicid; } } diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c index fa1c2ecacf..c90cbf9500 100644 --- a/xen/arch/x86/smpboot.c +++ b/xen/arch/x86/smpboot.c @@ -339,7 +339,7 @@ void asmlinkage start_secondary(void *unused) x2apic_ap_setup(); my_apicid = get_apic_id(); - while ( my_apicid != x86_cpu_to_apicid[cpu] ) { + while ( my_apicid != cpu_physical_id(cpu) ) { asm volatile ("monitor; xor %0,%0; mwait" :: "a"(__va(sinit_mle->rlp_wakeup_addr)), "c"(0), "d"(0) : "memory"); @@ -1213,7 +1213,7 @@ void __init smp_prepare_cpus(void) print_cpu_info(0); boot_cpu_physical_apicid = get_apic_id(); - x86_cpu_to_apicid[0] = boot_cpu_physical_apicid; + cpu_physical_id(0) = boot_cpu_physical_apicid; stack_base[0] = (void *)((unsigned long)stack_start & ~(STACK_SIZE - 1)); @@ -1433,7 +1433,7 @@ int __cpu_up(unsigned int cpu) { int apicid, ret; - if ( (apicid = x86_cpu_to_apicid[cpu]) == BAD_APICID ) + if ( (apicid = cpu_physical_id(cpu)) == BAD_APICID ) return -ENODEV; if ( (!x2apic_enabled && apicid >= APIC_ALL_CPUS) || diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c index 75a4177a75..21b974936f 100644 --- a/xen/arch/x86/spec_ctrl.c +++ b/xen/arch/x86/spec_ctrl.c @@ -707,7 +707,7 @@ static bool __init check_smt_enabled(void) * has a non-zero thread id component indicates that SMT is active. */ for_each_present_cpu ( cpu ) - if ( x86_cpu_to_apicid[cpu] & (boot_cpu_data.x86_num_siblings - 1) ) + if ( cpu_physical_id(cpu) & (boot_cpu_data.x86_num_siblings - 1) ) return true; return false; diff --git a/xen/arch/x86/sysctl.c b/xen/arch/x86/sysctl.c index 1b04947516..3aeca75909 100644 --- a/xen/arch/x86/sysctl.c +++ b/xen/arch/x86/sysctl.c @@ -58,7 +58,7 @@ static long cf_check smt_up_down_helper(void *data) for_each_present_cpu ( cpu ) { /* Skip primary siblings (those whose thread id is 0). */ - if ( !(x86_cpu_to_apicid[cpu] & sibling_mask) ) + if ( !(cpu_physical_id(cpu) & sibling_mask) ) continue; if ( !up && core_parking_remove(cpu) ) From c06e3409d5a6e1c7cf503b77926e3bc30199680a Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Thu, 1 Jun 2023 17:01:59 +0200 Subject: [PATCH 33/46] arch/x86/smp: drop x86_cpu_to_apicid, use cpu_data[cpu].apicid instead Both fields held the same data. Signed-off-by: Krystian Hebel --- xen/arch/x86/boot/x86_64.S | 8 +++++--- xen/arch/x86/include/asm/asm_defns.h | 2 +- xen/arch/x86/include/asm/processor.h | 2 ++ xen/arch/x86/include/asm/smp.h | 4 ---- xen/arch/x86/numa.c | 15 +++++++-------- xen/arch/x86/smpboot.c | 8 ++++---- xen/arch/x86/x86_64/asm-offsets.c | 4 +++- 7 files changed, 22 insertions(+), 21 deletions(-) diff --git a/xen/arch/x86/boot/x86_64.S b/xen/arch/x86/boot/x86_64.S index a86dc50f10..e8faaa7d5e 100644 --- a/xen/arch/x86/boot/x86_64.S +++ b/xen/arch/x86/boot/x86_64.S @@ -20,15 +20,17 @@ ENTRY(__high_start) jz .L_stack_set /* APs only: get stack base from APIC ID saved in %esp. */ - mov $-1, %rax - lea x86_cpu_to_apicid(%rip), %rcx + mov $0, %rax + lea cpu_data(%rip), %rcx + /* cpu_data[0] is BSP, skip it. */ 1: add $1, %rax + add $CPUINFO_X86_sizeof, %rcx cmp $NR_CPUS, %eax jb 2f hlt 2: - cmp %esp, (%rcx, %rax, 4) + cmp %esp, CPUINFO_X86_apicid(%rcx) jne 1b /* %eax is now Xen CPU index. */ diff --git a/xen/arch/x86/include/asm/asm_defns.h b/xen/arch/x86/include/asm/asm_defns.h index 92b4116a15..2a612c7003 100644 --- a/xen/arch/x86/include/asm/asm_defns.h +++ b/xen/arch/x86/include/asm/asm_defns.h @@ -167,7 +167,7 @@ register unsigned long current_stack_pointer asm("rsp"); #endif #define CPUINFO_FEATURE_OFFSET(feature) \ - (CPUINFO_features + (cpufeat_word(feature) * 4)) + (CPUINFO_X86_features + (cpufeat_word(feature) * 4)) #else diff --git a/xen/arch/x86/include/asm/processor.h b/xen/arch/x86/include/asm/processor.h index 39fcd42d91..1dce9c5a13 100644 --- a/xen/arch/x86/include/asm/processor.h +++ b/xen/arch/x86/include/asm/processor.h @@ -91,6 +91,8 @@ struct x86_cpu_id { extern struct cpuinfo_x86 cpu_data[]; #define current_cpu_data cpu_data[smp_processor_id()] +#define cpu_physical_id(cpu) cpu_data[cpu].apicid + extern bool probe_cpuid_faulting(void); extern void ctxt_switch_levelling(const struct vcpu *next); extern void (*ctxt_switch_masking)(const struct vcpu *next); diff --git a/xen/arch/x86/include/asm/smp.h b/xen/arch/x86/include/asm/smp.h index c8c7960134..6a1ad6d186 100644 --- a/xen/arch/x86/include/asm/smp.h +++ b/xen/arch/x86/include/asm/smp.h @@ -39,10 +39,6 @@ extern void (*mtrr_hook) (void); extern void zap_low_mappings(void); -extern u32 x86_cpu_to_apicid[]; - -#define cpu_physical_id(cpu) x86_cpu_to_apicid[cpu] - extern void cpu_exit_clear(unsigned int cpu); extern void cpu_uninit(unsigned int cpu); int cpu_add(uint32_t apic_id, uint32_t acpi_id, uint32_t pxm); diff --git a/xen/arch/x86/numa.c b/xen/arch/x86/numa.c index f0ec500be2..e0b2076c13 100644 --- a/xen/arch/x86/numa.c +++ b/xen/arch/x86/numa.c @@ -54,14 +54,13 @@ bool __init arch_numa_unavailable(void) /* * Setup early cpu_to_node. * - * Populate cpu_to_node[] only if x86_cpu_to_apicid[], - * and apicid_to_node[] tables have valid entries for a CPU. - * This means we skip cpu_to_node[] initialisation for NUMA - * emulation and faking node case (when running a kernel compiled - * for NUMA on a non NUMA box), which is OK as cpu_to_node[] - * is already initialized in a round robin manner at numa_init_array, - * prior to this call, and this initialization is good enough - * for the fake NUMA cases. + * Populate cpu_to_node[] only if cpu_data[], and apicid_to_node[] + * tables have valid entries for a CPU. This means we skip + * cpu_to_node[] initialisation for NUMA emulation and faking node + * case (when running a kernel compiled for NUMA on a non NUMA box), + * which is OK as cpu_to_node[] is already initialized in a round + * robin manner at numa_init_array, prior to this call, and this + * initialization is good enough for the fake NUMA cases. */ void __init init_cpu_to_node(void) { diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c index c90cbf9500..4e857bbd74 100644 --- a/xen/arch/x86/smpboot.c +++ b/xen/arch/x86/smpboot.c @@ -65,10 +65,8 @@ unsigned int __read_mostly nr_sockets; cpumask_t **__read_mostly socket_cpumask; static cpumask_t *secondary_socket_cpumask; -struct cpuinfo_x86 cpu_data[NR_CPUS]; - -u32 x86_cpu_to_apicid[NR_CPUS] __read_mostly = - { [0 ... NR_CPUS-1] = BAD_APICID }; +struct cpuinfo_x86 cpu_data[NR_CPUS] = + { [0 ... NR_CPUS-1] .apicid = BAD_APICID }; static int cpu_error; static enum cpu_state { @@ -85,7 +83,9 @@ void *stack_base[NR_CPUS]; void initialize_cpu_data(unsigned int cpu) { + uint32_t apicid = cpu_physical_id(cpu); cpu_data[cpu] = boot_cpu_data; + cpu_physical_id(cpu) = apicid; } static bool smp_store_cpu_info(unsigned int id) diff --git a/xen/arch/x86/x86_64/asm-offsets.c b/xen/arch/x86/x86_64/asm-offsets.c index 630bdc3945..93c490bd04 100644 --- a/xen/arch/x86/x86_64/asm-offsets.c +++ b/xen/arch/x86/x86_64/asm-offsets.c @@ -191,7 +191,9 @@ void __dummy__(void) OFFSET(IRQSTAT_softirq_pending, irq_cpustat_t, __softirq_pending); BLANK(); - OFFSET(CPUINFO_features, struct cpuinfo_x86, x86_capability); + OFFSET(CPUINFO_X86_features, struct cpuinfo_x86, x86_capability); + OFFSET(CPUINFO_X86_apicid, struct cpuinfo_x86, apicid); + DEFINE(CPUINFO_X86_sizeof, sizeof(struct cpuinfo_x86)); BLANK(); OFFSET(MB_flags, multiboot_info_t, flags); From 666b9bbeef45e92c077d51070b7a476f1a4e1b4f Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Tue, 19 Nov 2024 16:13:24 +0100 Subject: [PATCH 34/46] x86/setup.c: make stack_start constant Remove setting of this variable in do_boot_cpu(). It was not consumed after that point, and the only consumer is BSP which isn't booted through do_boot_cpu() in the first place. Signed-off-by: Krystian Hebel --- xen/arch/x86/include/asm/setup.h | 2 +- xen/arch/x86/setup.c | 4 ++-- xen/arch/x86/smpboot.c | 2 -- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/xen/arch/x86/include/asm/setup.h b/xen/arch/x86/include/asm/setup.h index 5c2391a868..7041a2a435 100644 --- a/xen/arch/x86/include/asm/setup.h +++ b/xen/arch/x86/include/asm/setup.h @@ -13,7 +13,7 @@ extern char __2M_rwdata_start[], __2M_rwdata_end[]; extern unsigned long xenheap_initial_phys_start; extern uint64_t boot_tsc_stamp; -extern void *stack_start; +extern void *const stack_start; extern unsigned int multiboot_ptr; void early_cpu_init(bool verbose); diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 8eab8adecf..fb58a83abe 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -156,8 +156,8 @@ unsigned long __read_mostly xen_phys_start; char asmlinkage __section(".init.bss.stack_aligned") __aligned(STACK_SIZE) cpu0_stack[STACK_SIZE]; -/* Used by the BSP/AP paths to find the higher half stack mapping to use. */ -void *stack_start = cpu0_stack + STACK_SIZE - sizeof(struct cpu_info); +/* Used by the BSP path to find the higher half stack mapping to use. */ +void *const stack_start = cpu0_stack + STACK_SIZE - sizeof(struct cpu_info); /* Used by the boot asm and EFI to stash the multiboot_info paddr. */ unsigned int __initdata multiboot_ptr; diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c index 4e857bbd74..a12576434d 100644 --- a/xen/arch/x86/smpboot.c +++ b/xen/arch/x86/smpboot.c @@ -631,8 +631,6 @@ static int do_boot_cpu(int apicid, int cpu) printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip); - stack_start = stack_base[cpu] + STACK_SIZE - sizeof(struct cpu_info); - /* This grunge runs the startup process for the targeted processor. */ set_cpu_state(CPU_STATE_INIT); From 226a2706a0b960b8780a692f2dd819bc3cadd481 Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Tue, 13 Jun 2023 15:44:36 +0200 Subject: [PATCH 35/46] arch/x86/smp: call x2apic_ap_setup() earlier It used to be called from smp_callin(), however BUG_ON() was invoked on multiple occasions before that. It may end up calling machine_restart() which tries to get APIC ID for CPU running this code. If BSP detected that x2APIC is enabled, get_apic_id() will try to use it for all CPUs. Enabling x2APIC on secondary CPUs earlier protects against an endless loop of #GP exceptions caused by attempts to read IA32_X2APIC_APICID MSR while x2APIC is disabled in IA32_APIC_BASE. Signed-off-by: Krystian Hebel --- xen/arch/x86/smpboot.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c index a12576434d..a0bf156594 100644 --- a/xen/arch/x86/smpboot.c +++ b/xen/arch/x86/smpboot.c @@ -186,7 +186,6 @@ static void smp_callin(void) * update until we finish. We are free to set up this CPU: first the APIC. */ Dprintk("CALLIN, before setup_local_APIC().\n"); - x2apic_ap_setup(); setup_local_APIC(false); /* Save our processor parameters. */ @@ -376,6 +375,14 @@ void asmlinkage start_secondary(void *unused) get_cpu_info()->xen_cr3 = 0; get_cpu_info()->pv_cr3 = 0; + /* + * BUG_ON() used in load_system_tables() and later code may end up calling + * machine_restart() which tries to get APIC ID for CPU running this code. + * If BSP detected that x2APIC is enabled, get_apic_id() will try to use it + * for _all_ CPUs. Enable x2APIC on secondary CPUs now so we won't end up + * with endless #GP loop. + */ + x2apic_ap_setup(); load_system_tables(); /* Full exception support from here on in. */ From 2bb4c2aa98515705e9d9b0936e7ab2aa91b7ab4a Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Tue, 13 Jun 2023 18:58:21 +0200 Subject: [PATCH 36/46] arch/x86/smp: drop booting_cpu variable CPU id is obtained as a side effect of searching for appropriate stack for AP. It can be used as a parameter to start_secondary(). Coincidentally this also makes further work on making AP bring-up code parallel easier. Signed-off-by: Krystian Hebel --- xen/arch/x86/boot/x86_64.S | 14 +++++++++----- xen/arch/x86/smpboot.c | 16 +++++----------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/xen/arch/x86/boot/x86_64.S b/xen/arch/x86/boot/x86_64.S index e8faaa7d5e..8c902ae7cd 100644 --- a/xen/arch/x86/boot/x86_64.S +++ b/xen/arch/x86/boot/x86_64.S @@ -20,22 +20,25 @@ ENTRY(__high_start) jz .L_stack_set /* APs only: get stack base from APIC ID saved in %esp. */ - mov $0, %rax + mov $0, %rbx lea cpu_data(%rip), %rcx /* cpu_data[0] is BSP, skip it. */ 1: - add $1, %rax + add $1, %rbx add $CPUINFO_X86_sizeof, %rcx - cmp $NR_CPUS, %eax + cmp $NR_CPUS, %rbx jb 2f hlt 2: cmp %esp, CPUINFO_X86_apicid(%rcx) jne 1b - /* %eax is now Xen CPU index. */ + /* + * %rbx (callee-save, as it will be passed to start_secondary() later) + * is now Xen CPU index. Use it to read stack base. + */ lea stack_base(%rip), %rcx - mov (%rcx, %rax, 8), %rsp + mov (%rcx, %rbx, 8), %rsp test %rsp,%rsp jnz 1f @@ -102,6 +105,7 @@ ENTRY(__high_start) .L_ap_cet_done: #endif /* CONFIG_XEN_SHSTK || CONFIG_XEN_IBT */ + mov %rbx, %rdi tailcall start_secondary .L_bsp: diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c index a0bf156594..c19f862c55 100644 --- a/xen/arch/x86/smpboot.c +++ b/xen/arch/x86/smpboot.c @@ -224,8 +224,6 @@ static void smp_callin(void) cpu_relax(); } -static int booting_cpu; - /* CPUs for which sibling maps can be computed. */ static cpumask_t cpu_sibling_setup_map; @@ -313,15 +311,14 @@ static void set_cpu_sibling_map(unsigned int cpu) } } -void asmlinkage start_secondary(void *unused) +void asmlinkage start_secondary(unsigned int cpu) { struct cpu_info *info = get_cpu_info(); /* - * Dont put anything before smp_callin(), SMP booting is so fragile that we + * Don't put anything before smp_callin(), SMP booting is so fragile that we * want to limit the things done here to the most necessary things. */ - unsigned int cpu = booting_cpu; if ( ap_boot_method == AP_BOOT_TXT ) { uint64_t misc_enable; @@ -342,7 +339,6 @@ void asmlinkage start_secondary(void *unused) asm volatile ("monitor; xor %0,%0; mwait" :: "a"(__va(sinit_mle->rlp_wakeup_addr)), "c"(0), "d"(0) : "memory"); - cpu = booting_cpu; } } @@ -371,9 +367,9 @@ void asmlinkage start_secondary(void *unused) */ spin_debug_disable(); - get_cpu_info()->use_pv_cr3 = false; - get_cpu_info()->xen_cr3 = 0; - get_cpu_info()->pv_cr3 = 0; + info->use_pv_cr3 = false; + info->xen_cr3 = 0; + info->pv_cr3 = 0; /* * BUG_ON() used in load_system_tables() and later code may end up calling @@ -625,8 +621,6 @@ static int do_boot_cpu(int apicid, int cpu) */ mtrr_save_state(); - booting_cpu = cpu; - start_eip = bootsym_phys(trampoline_realmode_entry); /* start_eip needs be page aligned, and below the 1M boundary. */ From ceefa86be5d3a138d30073189be2b090b83f0f35 Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Fri, 16 Jun 2023 12:18:23 +0200 Subject: [PATCH 37/46] arch/x86/smp: make cpu_state per-CPU This will be used for parallel AP bring-up. CPU_STATE_INIT changed direction. It was previously set by BSP and never consumed by AP. Now it signals that AP got through assembly part of initialization and waits for BSP to call notifiers that set up data structures required for further initialization. Signed-off-by: Krystian Hebel --- xen/arch/x86/smpboot.c | 75 +++++++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 31 deletions(-) diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c index c19f862c55..6b41591c2c 100644 --- a/xen/arch/x86/smpboot.c +++ b/xen/arch/x86/smpboot.c @@ -72,12 +72,15 @@ static int cpu_error; static enum cpu_state { CPU_STATE_DYING, /* slave -> master: I am dying */ CPU_STATE_DEAD, /* slave -> master: I am completely dead */ - CPU_STATE_INIT, /* master -> slave: Early bringup phase 1 */ - CPU_STATE_CALLOUT, /* master -> slave: Early bringup phase 2 */ + CPU_STATE_INIT, /* slave -> master: Early bringup phase 1 completed */ + CPU_STATE_CALLOUT, /* master -> slave: Start early bringup phase 2 */ CPU_STATE_CALLIN, /* slave -> master: Completed phase 2 */ CPU_STATE_ONLINE /* master -> slave: Go fully online now. */ -} cpu_state; -#define set_cpu_state(state) do { smp_mb(); cpu_state = (state); } while (0) +} cpu_state[NR_CPUS]; +#define set_cpu_state(cpu, state) do { \ + smp_mb(); \ + cpu_state[cpu] = (state); \ +} while (0) void *stack_base[NR_CPUS]; @@ -170,16 +173,7 @@ static void synchronize_tsc_slave(unsigned int slave) static void smp_callin(void) { unsigned int cpu = smp_processor_id(); - int i, rc; - - /* Wait 2s total for startup. */ - Dprintk("Waiting for CALLOUT.\n"); - for ( i = 0; cpu_state != CPU_STATE_CALLOUT; i++ ) - { - BUG_ON(i >= 200); - cpu_relax(); - mdelay(10); - } + int rc; /* * The boot CPU has finished the init stage and is spinning on cpu_state @@ -215,12 +209,12 @@ static void smp_callin(void) } /* Allow the master to continue. */ - set_cpu_state(CPU_STATE_CALLIN); + set_cpu_state(cpu, CPU_STATE_CALLIN); synchronize_tsc_slave(cpu); /* And wait for our final Ack. */ - while ( cpu_state != CPU_STATE_ONLINE ) + while ( cpu_state[cpu] != CPU_STATE_ONLINE ) cpu_relax(); } @@ -315,6 +309,9 @@ void asmlinkage start_secondary(unsigned int cpu) { struct cpu_info *info = get_cpu_info(); + /* Tell BSP that we are awake. */ + set_cpu_state(cpu, CPU_STATE_INIT); + /* * Don't put anything before smp_callin(), SMP booting is so fragile that we * want to limit the things done here to the most necessary things. @@ -344,6 +341,10 @@ void asmlinkage start_secondary(unsigned int cpu) /* Critical region without IDT or TSS. Any fault is deadly! */ + /* Wait until data set up by CPU_UP_PREPARE notifiers is ready. */ + while ( cpu_state[cpu] != CPU_STATE_CALLOUT ) + cpu_relax(); + set_current(idle_vcpu[cpu]); this_cpu(curr_vcpu) = idle_vcpu[cpu]; rdmsrl(MSR_EFER, this_cpu(efer)); @@ -634,26 +635,35 @@ static int do_boot_cpu(int apicid, int cpu) /* This grunge runs the startup process for the targeted processor. */ - set_cpu_state(CPU_STATE_INIT); - /* Starting actual IPI sequence... */ boot_error = wakeup_secondary_cpu(apicid, start_eip); if ( !boot_error ) { - /* Allow AP to start initializing. */ - set_cpu_state(CPU_STATE_CALLOUT); - Dprintk("After Callout %d.\n", cpu); - - /* Wait 5s total for a response. */ - for ( timeout = 0; timeout < 50000; timeout++ ) + /* Wait 2s total for a response. */ + for ( timeout = 0; timeout < 20000; timeout++ ) { - if ( cpu_state != CPU_STATE_CALLOUT ) + if ( cpu_state[cpu] == CPU_STATE_INIT ) break; udelay(100); } - if ( cpu_state == CPU_STATE_CALLIN ) + if ( cpu_state[cpu] == CPU_STATE_INIT ) + { + /* Allow AP to start initializing. */ + set_cpu_state(cpu, CPU_STATE_CALLOUT); + Dprintk("After Callout %d.\n", cpu); + + /* Wait 5s total for a response. */ + for ( timeout = 0; timeout < 500000; timeout++ ) + { + if ( cpu_state[cpu] != CPU_STATE_CALLOUT ) + break; + udelay(10); + } + } + + if ( cpu_state[cpu] == CPU_STATE_CALLIN ) { /* number CPUs logically, starting from 1 (BSP is 0) */ Dprintk("OK.\n"); @@ -661,7 +671,7 @@ static int do_boot_cpu(int apicid, int cpu) synchronize_tsc_master(cpu); Dprintk("CPU has booted.\n"); } - else if ( cpu_state == CPU_STATE_DEAD ) + else if ( cpu_state[cpu] == CPU_STATE_DEAD ) { smp_rmb(); rc = cpu_error; @@ -732,7 +742,7 @@ unsigned long alloc_stub_page(unsigned int cpu, unsigned long *mfn) void cpu_exit_clear(unsigned int cpu) { cpu_uninit(cpu); - set_cpu_state(CPU_STATE_DEAD); + set_cpu_state(cpu, CPU_STATE_DEAD); } static int clone_mapping(const void *ptr, root_pgentry_t *rpt) @@ -1216,6 +1226,9 @@ void __init smp_prepare_cpus(void) stack_base[0] = (void *)((unsigned long)stack_start & ~(STACK_SIZE - 1)); + /* Not really used anywhere, but set it just in case. */ + set_cpu_state(0, CPU_STATE_ONLINE); + set_nr_sockets(); socket_cpumask = xzalloc_array(cpumask_t *, nr_sockets); @@ -1322,7 +1335,7 @@ void __cpu_disable(void) { int cpu = smp_processor_id(); - set_cpu_state(CPU_STATE_DYING); + set_cpu_state(cpu, CPU_STATE_DYING); local_irq_disable(); clear_local_APIC(); @@ -1347,7 +1360,7 @@ void __cpu_die(unsigned int cpu) unsigned int i = 0; enum cpu_state seen_state; - while ( (seen_state = cpu_state) != CPU_STATE_DEAD ) + while ( (seen_state = cpu_state[cpu]) != CPU_STATE_DEAD ) { BUG_ON(seen_state != CPU_STATE_DYING); mdelay(100); @@ -1448,7 +1461,7 @@ int __cpu_up(unsigned int cpu) time_latch_stamps(); - set_cpu_state(CPU_STATE_ONLINE); + set_cpu_state(cpu, CPU_STATE_ONLINE); while ( !cpu_online(cpu) ) { cpu_relax(); From b6159cc6730814ec8a9ba1172d7445f1b3713325 Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Fri, 16 Jun 2023 14:31:27 +0200 Subject: [PATCH 38/46] arch/x86/smp: remove MONITOR/MWAIT loop for TXT AP bringup This is no longer necessary, since AP loops on cpu_state and CPU index is passed as argument. In addition, move TXT JOIN structure to static data. There is no guarantee that it would be consumed before it is overwritten on BSP stack. Signed-off-by: Krystian Hebel --- xen/arch/x86/smpboot.c | 37 +++++++++---------------------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c index 6b41591c2c..446c52d7bd 100644 --- a/xen/arch/x86/smpboot.c +++ b/xen/arch/x86/smpboot.c @@ -317,28 +317,6 @@ void asmlinkage start_secondary(unsigned int cpu) * want to limit the things done here to the most necessary things. */ - if ( ap_boot_method == AP_BOOT_TXT ) { - uint64_t misc_enable; - uint32_t my_apicid; - struct txt_sinit_mle_data *sinit_mle = - txt_sinit_mle_data_start(__va(read_txt_reg(TXTCR_HEAP_BASE))); - - /* TXT released us with MONITOR disabled in IA32_MISC_ENABLE. */ - rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable); - wrmsrl(MSR_IA32_MISC_ENABLE, - misc_enable | MSR_IA32_MISC_ENABLE_MONITOR_ENABLE); - - /* get_apic_id() reads from x2APIC if it thinks it is enabled. */ - x2apic_ap_setup(); - my_apicid = get_apic_id(); - - while ( my_apicid != cpu_physical_id(cpu) ) { - asm volatile ("monitor; xor %0,%0; mwait" - :: "a"(__va(sinit_mle->rlp_wakeup_addr)), "c"(0), - "d"(0) : "memory"); - } - } - /* Critical region without IDT or TSS. Any fault is deadly! */ /* Wait until data set up by CPU_UP_PREPARE notifiers is ready. */ @@ -452,13 +430,16 @@ static int wake_aps_in_txt(void) struct txt_sinit_mle_data *sinit_mle = txt_sinit_mle_data_start(__va(read_txt_reg(TXTCR_HEAP_BASE))); uint32_t *wakeup_addr = __va(sinit_mle->rlp_wakeup_addr); + static uint32_t join[4] = {0}; + + /* Check if already started. */ + if ( join[0] != 0 ) + return -1; - uint32_t join[4] = { - trampoline_gdt[1], /* GDT limit */ - bootsym_phys(trampoline_gdt), /* GDT base */ - TXT_AP_BOOT_CS, /* CS selector, DS = CS+8 */ - bootsym_phys(txt_ap_entry) /* EIP */ - }; + join[0] = trampoline_gdt[1]; /* GDT limit */ + join[1] = bootsym_phys(trampoline_gdt); /* GDT base */ + join[2] = TXT_AP_BOOT_CS; /* CS selector, DS = CS+8 */ + join[3] = bootsym_phys(txt_ap_entry); /* EIP */ write_txt_reg(TXTCR_MLE_JOIN, __pa(join)); From 6adad1a7ca978dfa04b1c31675b74aeb2caadc5f Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Fri, 16 Jun 2023 14:41:17 +0200 Subject: [PATCH 39/46] arch/x86/smp: don't send INIT-SIPI-SIPI if AP is already running This is another requirement for parallel AP bringup. Signed-off-by: Krystian Hebel --- xen/arch/x86/smpboot.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c index 446c52d7bd..e725ae3777 100644 --- a/xen/arch/x86/smpboot.c +++ b/xen/arch/x86/smpboot.c @@ -595,7 +595,6 @@ int alloc_cpu_id(void) static int do_boot_cpu(int apicid, int cpu) { int timeout, boot_error = 0, rc = 0; - unsigned long start_eip; /* * Save current MTRR state in case it was changed since early boot @@ -603,21 +602,31 @@ static int do_boot_cpu(int apicid, int cpu) */ mtrr_save_state(); - start_eip = bootsym_phys(trampoline_realmode_entry); + /* Check if AP is already up. */ + if ( cpu_state[cpu] != CPU_STATE_INIT ) + { + /* This grunge runs the startup process for the targeted processor. */ + unsigned long start_eip; + start_eip = bootsym_phys(trampoline_realmode_entry); - /* start_eip needs be page aligned, and below the 1M boundary. */ - if ( start_eip & ~0xff000 ) - panic("AP trampoline %#lx not suitably positioned\n", start_eip); + /* start_eip needs be page aligned, and below the 1M boundary. */ + if ( start_eip & ~0xff000 ) + panic("AP trampoline %#lx not suitably positioned\n", start_eip); - /* So we see what's up */ - if ( opt_cpu_info ) - printk("Booting processor %d/%d eip %lx\n", - cpu, apicid, start_eip); + /* So we see what's up */ + if ( opt_cpu_info ) + printk("AP trampoline at %lx\n", start_eip); - /* This grunge runs the startup process for the targeted processor. */ + /* mark "stuck" area as not stuck */ + bootsym(trampoline_cpu_started) = 0; + smp_mb(); - /* Starting actual IPI sequence... */ - boot_error = wakeup_secondary_cpu(apicid, start_eip); + /* Starting actual IPI sequence... */ + boot_error = wakeup_secondary_cpu(apicid, start_eip); + } + + if ( opt_cpu_info ) + printk("Booting processor %d/%d\n", cpu, apicid); if ( !boot_error ) { @@ -676,10 +685,6 @@ static int do_boot_cpu(int apicid, int cpu) rc = -EIO; } - /* mark "stuck" area as not stuck */ - bootsym(trampoline_cpu_started) = 0; - smp_mb(); - return rc; } From 96562e4861bfd08f9bb1f9f19c53bc47e5f78d23 Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Fri, 16 Jun 2023 15:45:32 +0200 Subject: [PATCH 40/46] arch/x86/smp: start APs in parallel during boot Multiple delays are required when sending IPIs and waiting for responses. During boot, 4 such IPIs were sent per each AP. With this change, only one set of broadcast IPIs is sent. This reduces boot time, especially for platforms with large number of cores. Single CPU initialization is still possible, it is used for hotplug. During wakeup from S3 APs are started one by one. It should be possible to enable parallel execution there as well, but I don't have a way of testing it as of now. Signed-off-by: Krystian Hebel --- xen/arch/x86/include/asm/smp.h | 1 + xen/arch/x86/setup.c | 2 ++ xen/arch/x86/smpboot.c | 31 +++++++++++++++++++++++++++---- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/xen/arch/x86/include/asm/smp.h b/xen/arch/x86/include/asm/smp.h index 6a1ad6d186..14ce3afaf6 100644 --- a/xen/arch/x86/include/asm/smp.h +++ b/xen/arch/x86/include/asm/smp.h @@ -31,6 +31,7 @@ DECLARE_PER_CPU(cpumask_var_t, send_ipi_cpumask); extern bool park_offline_cpus; void smp_send_nmi_allbutself(void); +void smp_send_init_sipi_sipi_allbutself(void); void send_IPI_mask(const cpumask_t *mask, int vector); void send_IPI_self(int vector); diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index fb58a83abe..202440818a 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -2069,6 +2069,8 @@ void asmlinkage __init noreturn __start_xen(void) stack_base[i] = cpu_alloc_stack(i); } + smp_send_init_sipi_sipi_allbutself(); + for_each_present_cpu ( i ) { if ( (park_offline_cpus || num_online_cpus() < max_cpus) && diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c index e725ae3777..81957f354d 100644 --- a/xen/arch/x86/smpboot.c +++ b/xen/arch/x86/smpboot.c @@ -452,7 +452,7 @@ static int wake_aps_in_txt(void) static int wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip) { - unsigned long send_status = 0, accept_status = 0; + unsigned long send_status = 0, accept_status = 0, sh = 0; int maxlvt, timeout, i; /* @@ -475,6 +475,12 @@ static int wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip) if ( ap_boot_method == AP_BOOT_TXT ) return wake_aps_in_txt(); + /* + * Use destination shorthand for broadcasting IPIs during boot. + */ + if ( phys_apicid == BAD_APICID ) + sh = APIC_DEST_ALLBUT; + /* * Be paranoid about clearing APIC errors. */ @@ -488,7 +494,7 @@ static int wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip) /* * Turn INIT on target chip via IPI */ - apic_icr_write(APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT, + apic_icr_write(APIC_INT_LEVELTRIG | APIC_INT_ASSERT | APIC_DM_INIT | sh, phys_apicid); if ( !x2apic_enabled ) @@ -505,7 +511,7 @@ static int wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip) Dprintk("Deasserting INIT.\n"); - apic_icr_write(APIC_INT_LEVELTRIG | APIC_DM_INIT, phys_apicid); + apic_icr_write(APIC_INT_LEVELTRIG | APIC_DM_INIT | sh, phys_apicid); Dprintk("Waiting for send to finish...\n"); timeout = 0; @@ -542,7 +548,7 @@ static int wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip) * STARTUP IPI * Boot on the stack */ - apic_icr_write(APIC_DM_STARTUP | (start_eip >> 12), phys_apicid); + apic_icr_write(APIC_DM_STARTUP | (start_eip >> 12) | sh, phys_apicid); if ( !x2apic_enabled ) { @@ -1190,6 +1196,23 @@ static struct notifier_block cpu_smpboot_nfb = { .notifier_call = cpu_smpboot_callback }; +void smp_send_init_sipi_sipi_allbutself(void) +{ + unsigned long start_eip; + start_eip = bootsym_phys(trampoline_realmode_entry); + + /* start_eip needs be page aligned, and below the 1M boundary. */ + if ( start_eip & ~0xff000 ) + panic("AP trampoline %#lx not suitably positioned\n", start_eip); + + /* So we see what's up */ + if ( opt_cpu_info ) + printk("Booting APs in parallel, eip %lx\n", start_eip); + + /* Starting actual broadcast IPI sequence... */ + wakeup_secondary_cpu(BAD_APICID, start_eip); +} + void __init smp_prepare_cpus(void) { /* From 7b7fcf970795cc889a2de370df297c6acf2168bf Mon Sep 17 00:00:00 2001 From: Krystian Hebel Date: Tue, 13 Jun 2023 15:56:12 +0200 Subject: [PATCH 41/46] arch/x86/shutdown: protect against recurrent machine_restart() If multiple CPUs called machine_restart() before actual restart took place, but after boot CPU declared itself not online, ASSERT in on_selected_cpus() will fail. Few calls later execution would end up in machine_restart() again, with another frame on call stack for new exception. To protect against running out of stack, code checks if boot CPU is still online before calling on_selected_cpus(). Signed-off-by: Krystian Hebel --- xen/arch/x86/shutdown.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/xen/arch/x86/shutdown.c b/xen/arch/x86/shutdown.c index 902076cf67..3ebac80257 100644 --- a/xen/arch/x86/shutdown.c +++ b/xen/arch/x86/shutdown.c @@ -549,9 +549,23 @@ void machine_restart(unsigned int delay_millisecs) /* Ensure we are the boot CPU. */ if ( get_apic_id() != boot_cpu_physical_apicid ) { - /* Send IPI to the boot CPU (logical cpu 0). */ - on_selected_cpus(cpumask_of(0), __machine_restart, - &delay_millisecs, 0); + /* + * Send IPI to the boot CPU (logical cpu 0). + * + * If multiple CPUs called machine_restart() before actual restart + * took place, but after boot CPU declared itself not online, ASSERT + * in on_selected_cpus() will fail. Few calls later we would end up + * here again, with another frame on call stack for new exception. + * To protect against running out of stack, check if boot CPU is + * online. + * + * Note this is not an atomic operation, so it is possible for + * on_selected_cpus() to be called once after boot CPU is offline + * before we hit halt() below. + */ + if ( cpu_online(0) ) + on_selected_cpus(cpumask_of(0), __machine_restart, + &delay_millisecs, 0); for ( ; ; ) halt(); } From acb6ceb94108e6fc30f7bd7f0afe5e286e47b42a Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Sun, 29 Oct 2023 00:42:04 +0300 Subject: [PATCH 42/46] arch/x86: process DRTM policy Go through entires in the DRTM policy of SLRT to hash and extend data that they describe into corresponding PCRs. Signed-off-by: Sergii Dmytruk Signed-off-by: Krystian Hebel --- xen/arch/x86/Makefile | 1 + xen/arch/x86/e820.c | 1 + xen/arch/x86/include/asm/intel_txt.h | 50 ------ xen/arch/x86/include/asm/slaunch.h | 54 ++++++ xen/arch/x86/include/asm/tpm.h | 11 ++ xen/arch/x86/intel_txt.c | 27 +-- xen/arch/x86/setup.c | 13 ++ xen/arch/x86/slaunch.c | 247 +++++++++++++++++++++++++++ xen/arch/x86/smpboot.c | 1 + xen/arch/x86/tpm.c | 3 +- 10 files changed, 331 insertions(+), 77 deletions(-) create mode 100644 xen/arch/x86/include/asm/slaunch.h create mode 100644 xen/arch/x86/slaunch.c diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index f0fce48454..66e10ad9e2 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -60,6 +60,7 @@ obj-$(CONFIG_X86_PSR) += psr.o obj-y += intel_txt.o obj-y += setup.o obj-y += shutdown.o +obj-y += slaunch.o obj-y += smp.o obj-y += smpboot.o obj-y += spec_ctrl.o diff --git a/xen/arch/x86/e820.c b/xen/arch/x86/e820.c index c8d14b55a7..3892f901b5 100644 --- a/xen/arch/x86/e820.c +++ b/xen/arch/x86/e820.c @@ -12,6 +12,7 @@ #include #include #include +#include /* * opt_mem: Limit maximum address of physical RAM. diff --git a/xen/arch/x86/include/asm/intel_txt.h b/xen/arch/x86/include/asm/intel_txt.h index d33469166f..888a6e67b1 100644 --- a/xen/arch/x86/include/asm/intel_txt.h +++ b/xen/arch/x86/include/asm/intel_txt.h @@ -80,8 +80,6 @@ #ifndef __ASSEMBLY__ -extern bool slaunch_active; - extern char txt_ap_entry[]; extern uint32_t trampoline_gdt[]; @@ -95,8 +93,6 @@ extern uint32_t trampoline_gdt[]; #define _txt(x) __va(x) #endif -#include - /* * Always use private space as some of registers are either read-only or not * present in public space. @@ -334,39 +330,6 @@ static inline int is_in_pmr(struct txt_os_sinit_data *os_sinit, uint64_t base, return 0; } -/* - * This helper function is used to map memory using L2 page tables by aligning - * mapped regions to 2MB. This way page allocator (which at this point isn't - * yet initialized) isn't needed for creating new L1 mappings. The function - * also checks and skips memory already mapped by the prebuilt tables. - * - * There is no unmap_l2() because the function is meant to be used for code that - * accesses TXT registers and TXT heap soon after which Xen rebuilds memory - * maps, effectively dropping all existing mappings. - */ -extern int map_l2(unsigned long paddr, unsigned long size); - -/* evt_log is a physical address and the caller must map it to virtual, if - * needed. */ -static inline void find_evt_log(struct slr_table *slrt, void **evt_log, - uint32_t *evt_log_size) -{ - struct slr_entry_log_info *log_info; - - log_info = (struct slr_entry_log_info *) - slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_LOG_INFO); - if ( log_info != NULL ) - { - *evt_log = _p(log_info->addr); - *evt_log_size = log_info->size; - } - else - { - *evt_log = NULL; - *evt_log_size = 0; - } -} - /* Returns physical address. */ static inline uint32_t txt_find_slrt(void) { @@ -379,17 +342,4 @@ extern void map_txt_mem_regions(void); extern void protect_txt_mem_regions(void); extern void txt_restore_mtrrs(bool e820_verbose); -#define DRTM_LOC 2 -#define DRTM_CODE_PCR 17 -#define DRTM_DATA_PCR 18 - -/* - * Secure Launch event log entry type. The TXT specification defines the - * base event value as 0x400 for DRTM values. - */ -#define TXT_EVTYPE_BASE 0x400 -#define TXT_EVTYPE_SLAUNCH (TXT_EVTYPE_BASE + 0x102) -#define TXT_EVTYPE_SLAUNCH_START (TXT_EVTYPE_BASE + 0x103) -#define TXT_EVTYPE_SLAUNCH_END (TXT_EVTYPE_BASE + 0x104) - #endif /* __ASSEMBLY__ */ diff --git a/xen/arch/x86/include/asm/slaunch.h b/xen/arch/x86/include/asm/slaunch.h new file mode 100644 index 0000000000..03c686061a --- /dev/null +++ b/xen/arch/x86/include/asm/slaunch.h @@ -0,0 +1,54 @@ +#ifndef _ASM_X86_SLAUNCH_H_ +#define _ASM_X86_SLAUNCH_H_ + +#include +#include + +#define DRTM_LOC 2 +#define DRTM_CODE_PCR 17 +#define DRTM_DATA_PCR 18 + +/* + * Secure Launch event log entry types. The TXT specification defines the + * base event value as 0x400 for DRTM values. + */ +#define TXT_EVTYPE_BASE 0x400 +#define DLE_EVTYPE_SLAUNCH (TXT_EVTYPE_BASE + 0x102) +#define DLE_EVTYPE_SLAUNCH_START (TXT_EVTYPE_BASE + 0x103) +#define DLE_EVTYPE_SLAUNCH_END (TXT_EVTYPE_BASE + 0x104) + +extern bool slaunch_active; + +/* evt_log is a physical address and the caller must map it to virtual, if + * needed. */ +static inline void find_evt_log(struct slr_table *slrt, void **evt_log, + uint32_t *evt_log_size) +{ + struct slr_entry_log_info *log_info = + (void *)slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_LOG_INFO); + + if ( log_info != NULL ) + { + *evt_log = _p(log_info->addr); + *evt_log_size = log_info->size; + } + else + { + *evt_log = NULL; + *evt_log_size = 0; + } +} + +/* + * This helper function is used to map memory using L2 page tables by aligning + * mapped regions to 2MB. This way page allocator (which at this point isn't + * yet initialized) isn't needed for creating new L1 mappings. The function + * also checks and skips memory already mapped by the prebuilt tables. + * + * There is no unmap_l2() because the function is meant to be used for code that + * accesses TXT registers and TXT heap soon after which Xen rebuilds memory + * maps, effectively dropping all existing mappings. + */ +extern int map_l2(unsigned long paddr, unsigned long size); + +#endif /* _ASM_X86_SLAUNCH_H_ */ diff --git a/xen/arch/x86/include/asm/tpm.h b/xen/arch/x86/include/asm/tpm.h index 9bbdf63680..3a0b291358 100644 --- a/xen/arch/x86/include/asm/tpm.h +++ b/xen/arch/x86/include/asm/tpm.h @@ -1,6 +1,7 @@ #ifndef _ASM_X86_TPM_H_ #define _ASM_X86_TPM_H_ +#include #include #define TPM_TIS_BASE 0xFED40000 @@ -9,4 +10,14 @@ void tpm_hash_extend(unsigned loc, unsigned pcr, uint8_t *buf, unsigned size, uint32_t type, uint8_t *log_data, unsigned log_data_size); +/* Measures essential parts of SLR table before making use of them. */ +void tpm_measure_slrt(void); + +/* Takes measurements of DRTM policy entries except for MBI and SLRT which + * should have been measured by the time this is called. Also performs sanity + * checks of the policy and panics on failure. In particular, the function + * verifies that DRTM is consistent with modules obtained from MultibootInfo + * (MBI) and written to struct boot_info in setup.c. */ +void tpm_process_drtm_policy(const struct boot_info *bi); + #endif /* _ASM_X86_TPM_H_ */ diff --git a/xen/arch/x86/intel_txt.c b/xen/arch/x86/intel_txt.c index f07a1044ee..36fda89cf2 100644 --- a/xen/arch/x86/intel_txt.c +++ b/xen/arch/x86/intel_txt.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -12,32 +13,6 @@ static uint64_t __initdata txt_heap_base, txt_heap_size; -bool __initdata slaunch_active; - -static void __maybe_unused compile_time_checks(void) -{ - BUILD_BUG_ON(sizeof(slaunch_active) != 1); -} - -int __init map_l2(unsigned long paddr, unsigned long size) -{ - unsigned long aligned_paddr = paddr & ~((1ULL << L2_PAGETABLE_SHIFT) - 1); - unsigned long pages = ((paddr + size) - aligned_paddr); - pages = ROUNDUP(pages, 1ULL << L2_PAGETABLE_SHIFT) >> PAGE_SHIFT; - - if ( (aligned_paddr + pages * PAGE_SIZE) <= PREBUILT_MAP_LIMIT ) - return 0; - - if ( aligned_paddr < PREBUILT_MAP_LIMIT ) { - pages -= (PREBUILT_MAP_LIMIT - aligned_paddr) >> PAGE_SHIFT; - aligned_paddr = PREBUILT_MAP_LIMIT; - } - - return map_pages_to_xen((unsigned long)__va(aligned_paddr), - maddr_to_mfn(aligned_paddr), - pages, PAGE_HYPERVISOR); -} - void __init map_txt_mem_regions(void) { void *evt_log_addr; diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 202440818a..27f77fd1c9 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -63,6 +63,8 @@ #include #include #include +#include +#include /* opt_nosmp: If true, secondary processors are ignored. */ static bool __initdata opt_nosmp; @@ -1388,6 +1390,9 @@ void asmlinkage __init noreturn __start_xen(void) { /* Prepare for TXT-related code. */ map_txt_mem_regions(); + /* Measure SLRT here because it gets used by init_e820(), the rest is + * measured below by tpm_process_drtm_policy(). */ + tpm_measure_slrt(); /* Reserve TXT heap and SINIT. */ protect_txt_mem_regions(); } @@ -1410,6 +1415,14 @@ void asmlinkage __init noreturn __start_xen(void) /* Create a temporary copy of the E820 map. */ memcpy(&boot_e820, &e820, sizeof(e820)); + /* + * Process all yet unmeasured DRTM entries after E820 initialization to not + * do this while memory is uncached (too slow). This must also happen before + * modules are relocated or used. + */ + if ( slaunch_active ) + tpm_process_drtm_policy(bi); + /* Early kexec reservation (explicit static start address). */ nr_pages = 0; for ( i = 0; i < e820.nr_map; i++ ) diff --git a/xen/arch/x86/slaunch.c b/xen/arch/x86/slaunch.c new file mode 100644 index 0000000000..f8f3f1aa57 --- /dev/null +++ b/xen/arch/x86/slaunch.c @@ -0,0 +1,247 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +bool __initdata slaunch_active; + +static void __maybe_unused compile_time_checks(void) +{ + BUILD_BUG_ON(sizeof(slaunch_active) != 1); +} + +int __init map_l2(unsigned long paddr, unsigned long size) +{ + unsigned long aligned_paddr = paddr & ~((1ULL << L2_PAGETABLE_SHIFT) - 1); + unsigned long pages = ((paddr + size) - aligned_paddr); + pages = ROUNDUP(pages, 1ULL << L2_PAGETABLE_SHIFT) >> PAGE_SHIFT; + + if ( (aligned_paddr + pages * PAGE_SIZE) <= PREBUILT_MAP_LIMIT ) + return 0; + + if ( aligned_paddr < PREBUILT_MAP_LIMIT ) + { + pages -= (PREBUILT_MAP_LIMIT - aligned_paddr) >> PAGE_SHIFT; + aligned_paddr = PREBUILT_MAP_LIMIT; + } + + return map_pages_to_xen((unsigned long)__va(aligned_paddr), + maddr_to_mfn(aligned_paddr), + pages, PAGE_HYPERVISOR); +} + +static struct slr_table *slr_get_table(void) +{ + uint32_t slrt_pa = txt_find_slrt(); + struct slr_table *slrt = __va(slrt_pa); + + map_l2(slrt_pa, PAGE_SIZE); + + if ( slrt->magic != SLR_TABLE_MAGIC ) + panic("SLRT has invalid magic value: %#08x!\n", slrt->magic); + /* XXX: are newer revisions allowed? */ + if ( slrt->revision != SLR_TABLE_REVISION ) + panic("SLRT is of unsupported revision: %#04x!\n", slrt->revision); + if ( slrt->architecture != SLR_INTEL_TXT ) + panic("SLRT is for unexpected architecture: %#04x!\n", + slrt->architecture); + if ( slrt->size > slrt->max_size ) + panic("SLRT is larger than its max size: %#08x > %#08x!\n", + slrt->size, slrt->max_size); + + if ( slrt->size > PAGE_SIZE ) + map_l2(slrt_pa, slrt->size); + + return slrt; +} + +void tpm_measure_slrt(void) +{ + struct slr_table *slrt = slr_get_table(); + + if ( slrt->revision == 1 ) + { + /* In revision one of the SLRT, only Intel info table is measured. */ + struct slr_entry_intel_info *intel_info = + (void *)slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_INTEL_INFO); + if ( intel_info == NULL ) + panic("SLRT is missing Intel-specific information!\n"); + + tpm_hash_extend(DRTM_LOC, DRTM_DATA_PCR, (uint8_t *)intel_info, + sizeof(*intel_info), DLE_EVTYPE_SLAUNCH, NULL, 0); + } + else + { + /* + * slr_get_table() checks that the revision is valid, so we must not + * get here unless the code is wrong. + */ + panic("Unhandled SLRT revision: %d!\n", slrt->revision); + } +} + +static struct slr_entry_policy *slr_get_policy(struct slr_table *slrt) +{ + struct slr_entry_policy *policy; + + policy = (struct slr_entry_policy *) + slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_DRTM_POLICY); + if (policy == NULL) + panic("SLRT is missing DRTM policy!\n"); + + /* XXX: are newer revisions allowed? */ + if ( policy->revision != SLR_POLICY_REVISION ) + panic("DRTM policy in SLRT is of unsupported revision: %#04x!\n", + slrt->revision); + + return policy; +} + +static void check_drtm_policy(struct slr_table *slrt, + struct slr_entry_policy *policy, + struct slr_policy_entry *policy_entry, + const struct boot_info *bi) +{ + uint32_t i; + uint32_t num_mod_entries; + + if ( policy->nr_entries < 2 ) + panic("DRTM policy in SLRT contains less than 2 entries (%d)!\n", + policy->nr_entries); + + /* MBI policy entry must be the first one, so that measuring order matches + * policy order. */ + if ( policy_entry[0].entity_type != SLR_ET_MULTIBOOT2_INFO ) + panic("First entry of DRTM policy in SLRT is not MBI: %#04x!\n", + policy_entry[0].entity_type); + if ( policy_entry[0].pcr != DRTM_DATA_PCR ) + panic("MBI was measured to %d instead of %d PCR!\n", DRTM_DATA_PCR, + policy_entry[0].pcr); + + /* SLRT policy entry must be the second one. */ + if ( policy_entry[1].entity_type != SLR_ET_SLRT ) + panic("Second entry of DRTM policy in SLRT is not SLRT: %#04x!\n", + policy_entry[1].entity_type); + if ( policy_entry[1].pcr != DRTM_DATA_PCR ) + panic("SLRT was measured to %d instead of %d PCR!\n", DRTM_DATA_PCR, + policy_entry[1].pcr); + if ( policy_entry[1].entity != (uint64_t)__pa(slrt) ) + panic("SLRT address (%#08lx) differes from its DRTM entry (%#08lx)\n", + __pa(slrt), policy_entry[1].entity); + + /* + * XXX: this loop uses transitionary format of struct boot_module, added in + * 7cf6e073e47 "x86/boot: introduce struct boot_module", and will have to + * be updated if that definition changes. + */ + for ( i = 0; i < bi->nr_modules; i++ ) + { + uint16_t j; + const struct boot_module *mod = &bi->mods[i]; + + if (mod->relocated || mod->released) + { + panic("Multiboot module \"%s\" (at %d) was consumed before measurement\n", + (const char *)__va(mod->cmdline_pa), i); + } + + for ( j = 2; j < policy->nr_entries; j++ ) + { + if ( policy_entry[j].entity_type != SLR_ET_MULTIBOOT2_MODULE ) + continue; + + if ( policy_entry[j].entity == mod->start && + policy_entry[j].size == mod->size ) + break; + } + + if ( j >= policy->nr_entries ) + { + panic("Couldn't find Multiboot module \"%s\" (at %d) in DRTM of Secure Launch\n", + (const char *)__va(mod->cmdline_pa), i); + } + } + + num_mod_entries = 0; + for ( i = 0; i < policy->nr_entries; i++ ) + { + if ( policy_entry[i].entity_type == SLR_ET_MULTIBOOT2_MODULE ) + num_mod_entries++; + } + + if ( bi->nr_modules != num_mod_entries ) + { + panic("Unexpected number of Multiboot modules: %d instead of %d\n", + (int)bi->nr_modules, (int)num_mod_entries); + } +} + +void tpm_process_drtm_policy(const struct boot_info *bi) +{ + struct slr_table *slrt; + struct slr_entry_policy *policy; + struct slr_policy_entry *policy_entry; + uint16_t i; + + slrt = slr_get_table(); + + policy = slr_get_policy(slrt); + policy_entry = (struct slr_policy_entry *) + ((uint8_t *)policy + sizeof(*policy)); + + check_drtm_policy(slrt, policy, policy_entry, bi); + /* MBI was measured in tpm_extend_mbi(). */ + policy_entry[0].flags |= SLR_POLICY_FLAG_MEASURED; + /* SLRT was measured in tpm_measure_slrt(). */ + policy_entry[1].flags |= SLR_POLICY_FLAG_MEASURED; + + for ( i = 2; i < policy->nr_entries; i++ ) + { + uint64_t start = policy_entry[i].entity; + uint64_t size = policy_entry[i].size; + + /* No already measured entries are expected here. */ + if ( policy_entry[i].flags & SLR_POLICY_FLAG_MEASURED ) + panic("DRTM entry at %d was measured out of order!\n", i); + + switch ( policy_entry[i].entity_type ) + { + case SLR_ET_MULTIBOOT2_INFO: + panic("Duplicated MBI entry in DRTM of Secure Launch at %d\n", i); + case SLR_ET_SLRT: + panic("Duplicated SLRT entry in DRTM of Secure Launch at %d\n", i); + + case SLR_ET_UNSPECIFIED: + case SLR_ET_BOOT_PARAMS: + case SLR_ET_SETUP_DATA: + case SLR_ET_CMDLINE: + case SLR_ET_UEFI_MEMMAP: + case SLR_ET_RAMDISK: + case SLR_ET_MULTIBOOT2_MODULE: + case SLR_ET_TXT_OS2MLE: + /* Measure this entry below. */ + break; + + case SLR_ET_UNUSED: + /* Skip this entry. */ + continue; + } + + if ( policy_entry[i].flags & SLR_POLICY_IMPLICIT_SIZE ) + panic("Unexpected implicitly-sized DRTM entry of Secure Launch at %d\n", + i); + + map_l2(start, size); + tpm_hash_extend(DRTM_LOC, policy_entry[i].pcr, __va(start), size, + DLE_EVTYPE_SLAUNCH, (uint8_t *)policy_entry[i].evt_info, + strnlen(policy_entry[i].evt_info, + TPM_EVENT_INFO_LENGTH)); + + policy_entry[i].flags |= SLR_POLICY_FLAG_MEASURED; + } +} diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c index 81957f354d..5f8e8fd9ba 100644 --- a/xen/arch/x86/smpboot.c +++ b/xen/arch/x86/smpboot.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include diff --git a/xen/arch/x86/tpm.c b/xen/arch/x86/tpm.c index 90056cda8e..9040f4312a 100644 --- a/xen/arch/x86/tpm.c +++ b/xen/arch/x86/tpm.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #ifdef __EARLY_TPM__ @@ -966,6 +967,6 @@ void tpm_extend_mbi(uint32_t *mbi) { /* MBI starts with uint32_t total_size. */ tpm_hash_extend(DRTM_LOC, DRTM_DATA_PCR, (uint8_t *)mbi, *mbi, - TXT_EVTYPE_SLAUNCH, NULL, 0); + DLE_EVTYPE_SLAUNCH, NULL, 0); } #endif From 6bacd4534c40e5265053bda94164f72800c92d8c Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Thu, 21 Mar 2024 19:35:10 +0200 Subject: [PATCH 43/46] x86/boot: introduce slaunch_slrt global variable It holds physical address of SLRT. The value is produced by slaunch_early (known as txt_early previously), gets set in assembly and then used by the main C code which don't need to know how we got it (which is different for different CPUs). This change additionally renames txt_early.c into slaunch_early.c Signed-off-by: Sergii Dmytruk Signed-off-by: Krystian Hebel --- xen/arch/x86/boot/Makefile | 4 +-- xen/arch/x86/boot/head.S | 29 ++++++++++++++----- .../x86/boot/{txt_early.c => slaunch_early.c} | 14 +++++++-- xen/arch/x86/include/asm/intel_txt.h | 8 ----- xen/arch/x86/include/asm/slaunch.h | 1 + xen/arch/x86/intel_txt.c | 4 +-- xen/arch/x86/slaunch.c | 9 +++--- xen/arch/x86/tpm.c | 12 +++++--- 8 files changed, 50 insertions(+), 31 deletions(-) rename xen/arch/x86/boot/{txt_early.c => slaunch_early.c} (93%) diff --git a/xen/arch/x86/boot/Makefile b/xen/arch/x86/boot/Makefile index 6a9e27b18a..5b4a9129f9 100644 --- a/xen/arch/x86/boot/Makefile +++ b/xen/arch/x86/boot/Makefile @@ -5,7 +5,7 @@ obj-bin-y += $(obj64) obj32 := cmdline.32.o obj32 += reloc.32.o obj32 += reloc-trampoline.32.o -obj32 += txt_early.32.o +obj32 += slaunch_early.32.o obj32 += tpm_early.32.o obj64 := reloc-trampoline.o @@ -86,7 +86,7 @@ cmd_combine = \ --bin1 $(obj)/built-in-32.base.bin \ --bin2 $(obj)/built-in-32.offset.bin \ --map $(obj)/built-in-32.base.map \ - --exports cmdline_parse_early,reloc,reloc_trampoline32,txt_early_tests,tpm_extend_mbi \ + --exports cmdline_parse_early,reloc,reloc_trampoline32,slaunch_early_tests,tpm_extend_mbi \ --output $@ targets += built-in-32.S diff --git a/xen/arch/x86/boot/head.S b/xen/arch/x86/boot/head.S index 98cfa3f92f..f593df9c9f 100644 --- a/xen/arch/x86/boot/head.S +++ b/xen/arch/x86/boot/head.S @@ -492,20 +492,35 @@ __start: jmp trampoline_bios_setup .Lslaunch_proto: + /* Upon reaching here, CPU state mostly matches the one setup by the + * bootloader with ESP, ESI and EDX being clobbered above. */ + /* Save information that TrenchBoot slaunch was used. */ movb $1, sym_esi(slaunch_active) + /* Prepare space for output parameter of slaunch_early_tests(), which is + * a structure of two uint32_t fields. */ + sub $8, %esp + + push %esp /* pointer to output structure */ lea sym_offs(__2M_rwdata_end), %ecx /* end of target image */ lea sym_offs(_start), %edx /* target base address */ mov %esi, %eax /* load base address */ - /* txt_early_tests(load/eax, tgt/edx, tgt_end/ecx) using fastcall. */ - call txt_early_tests + /* slaunch_early_tests(load/eax, tgt/edx, tgt_end/ecx, ret/stk) using fastcall. */ + call slaunch_early_tests + add $4, %esp - /* - * txt_early_tests() returns MBI address, pass it to tpm_extend_mbi() - * and store for later in EBX. - */ - movl %eax, %ebx + /* Move outputs of slaunch_early_tests() from stack into registers. */ + pop %eax /* physical MBI address */ + pop %edx /* physical SLRT address */ + + /* Save physical address of SLRT for C code. */ + mov %edx, sym_esi(slaunch_slrt) + + /* Store MBI address in EBX where MB2 code expects it. */ + mov %eax, %ebx + + /* tpm_extend_mbi(mbi/eax, slrt/edx) using fastcall. */ call tpm_extend_mbi /* Move magic number expected by Multiboot 2 to EAX and fall through. */ diff --git a/xen/arch/x86/boot/txt_early.c b/xen/arch/x86/boot/slaunch_early.c similarity index 93% rename from xen/arch/x86/boot/txt_early.c rename to xen/arch/x86/boot/slaunch_early.c index dcbddf057c..e818415a2d 100644 --- a/xen/arch/x86/boot/txt_early.c +++ b/xen/arch/x86/boot/slaunch_early.c @@ -19,6 +19,12 @@ #include #include +struct early_tests_results +{ + uint32_t mbi_pa; + uint32_t slrt_pa; +} __packed; + static void verify_pmr_ranges(struct txt_os_mle_data *os_mle, struct txt_os_sinit_data *os_sinit, uint32_t load_base_addr, uint32_t tgt_base_addr, @@ -95,9 +101,10 @@ static void verify_pmr_ranges(struct txt_os_mle_data *os_mle, */ } -uint32_t txt_early_tests(uint32_t load_base_addr, +void slaunch_early_tests(uint32_t load_base_addr, uint32_t tgt_base_addr, - uint32_t tgt_end_addr) + uint32_t tgt_end_addr, + struct early_tests_results *result) { void *txt_heap; struct txt_os_mle_data *os_mle; @@ -118,5 +125,6 @@ uint32_t txt_early_tests(uint32_t load_base_addr, verify_pmr_ranges(os_mle, os_sinit, load_base_addr, tgt_base_addr, size); - return os_mle->boot_params_addr; + result->mbi_pa = os_mle->boot_params_addr; + result->slrt_pa = os_mle->slrt; } diff --git a/xen/arch/x86/include/asm/intel_txt.h b/xen/arch/x86/include/asm/intel_txt.h index 888a6e67b1..2ec1a2ed73 100644 --- a/xen/arch/x86/include/asm/intel_txt.h +++ b/xen/arch/x86/include/asm/intel_txt.h @@ -330,14 +330,6 @@ static inline int is_in_pmr(struct txt_os_sinit_data *os_sinit, uint64_t base, return 0; } -/* Returns physical address. */ -static inline uint32_t txt_find_slrt(void) -{ - struct txt_os_mle_data *os_mle = - txt_os_mle_data_start(_txt(read_txt_reg(TXTCR_HEAP_BASE))); - return os_mle->slrt; -} - extern void map_txt_mem_regions(void); extern void protect_txt_mem_regions(void); extern void txt_restore_mtrrs(bool e820_verbose); diff --git a/xen/arch/x86/include/asm/slaunch.h b/xen/arch/x86/include/asm/slaunch.h index 03c686061a..70101bb5d6 100644 --- a/xen/arch/x86/include/asm/slaunch.h +++ b/xen/arch/x86/include/asm/slaunch.h @@ -18,6 +18,7 @@ #define DLE_EVTYPE_SLAUNCH_END (TXT_EVTYPE_BASE + 0x104) extern bool slaunch_active; +extern uint32_t slaunch_slrt; /* physical address */ /* evt_log is a physical address and the caller must map it to virtual, if * needed. */ diff --git a/xen/arch/x86/intel_txt.c b/xen/arch/x86/intel_txt.c index 36fda89cf2..c3471dfe1f 100644 --- a/xen/arch/x86/intel_txt.c +++ b/xen/arch/x86/intel_txt.c @@ -29,7 +29,7 @@ void __init map_txt_mem_regions(void) map_l2(txt_heap_base, txt_heap_size); - find_evt_log(__va(txt_find_slrt()), &evt_log_addr, &evt_log_size); + find_evt_log(__va(slaunch_slrt), &evt_log_addr, &evt_log_size); map_l2((unsigned long)evt_log_addr, evt_log_size); if ( evt_log_addr != NULL ) map_l2((unsigned long)evt_log_addr, evt_log_size); @@ -53,7 +53,7 @@ void __init protect_txt_mem_regions(void) BUG_ON(rc == 0); /* TXT TPM Event Log */ - find_evt_log(__va(txt_find_slrt()), &evt_log_addr, &evt_log_size); + find_evt_log(__va(slaunch_slrt), &evt_log_addr, &evt_log_size); if ( evt_log_addr != NULL ) { printk("SLAUNCH: reserving event log (%#lx - %#lx)\n", (uint64_t)evt_log_addr, diff --git a/xen/arch/x86/slaunch.c b/xen/arch/x86/slaunch.c index f8f3f1aa57..b4c3b2b851 100644 --- a/xen/arch/x86/slaunch.c +++ b/xen/arch/x86/slaunch.c @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -9,6 +8,7 @@ #include bool __initdata slaunch_active; +uint32_t __initdata slaunch_slrt; static void __maybe_unused compile_time_checks(void) { @@ -37,10 +37,9 @@ int __init map_l2(unsigned long paddr, unsigned long size) static struct slr_table *slr_get_table(void) { - uint32_t slrt_pa = txt_find_slrt(); - struct slr_table *slrt = __va(slrt_pa); + struct slr_table *slrt = __va(slaunch_slrt); - map_l2(slrt_pa, PAGE_SIZE); + map_l2(slaunch_slrt, PAGE_SIZE); if ( slrt->magic != SLR_TABLE_MAGIC ) panic("SLRT has invalid magic value: %#08x!\n", slrt->magic); @@ -55,7 +54,7 @@ static struct slr_table *slr_get_table(void) slrt->size, slrt->max_size); if ( slrt->size > PAGE_SIZE ) - map_l2(slrt_pa, slrt->size); + map_l2(slaunch_slrt, slrt->size); return slrt; } diff --git a/xen/arch/x86/tpm.c b/xen/arch/x86/tpm.c index 9040f4312a..6596a72379 100644 --- a/xen/arch/x86/tpm.c +++ b/xen/arch/x86/tpm.c @@ -30,6 +30,8 @@ #define __va(x) _p(x) +uint32_t slaunch_slrt; + /* * The code is being compiled as a standalone binary without linking to any * other part of Xen. Providing implementation of builtin functions in this @@ -923,9 +925,7 @@ void tpm_hash_extend(unsigned loc, unsigned pcr, uint8_t *buf, unsigned size, void *evt_log_addr; uint32_t evt_log_size; - struct slr_table *slrt = __va(txt_find_slrt()); - - find_evt_log(slrt, &evt_log_addr, &evt_log_size); + find_evt_log(__va(slaunch_slrt), &evt_log_addr, &evt_log_size); evt_log_addr = __va((uintptr_t)evt_log_addr); if ( is_tpm12() ) { @@ -963,8 +963,12 @@ void tpm_hash_extend(unsigned loc, unsigned pcr, uint8_t *buf, unsigned size, } #ifdef __EARLY_TPM__ -void tpm_extend_mbi(uint32_t *mbi) +void tpm_extend_mbi(uint32_t *mbi, uint32_t slrt_pa) { + /* Early TPM code isn't linked with the rest but still needs to have this + * variable with correct value. */ + slaunch_slrt = slrt_pa; + /* MBI starts with uint32_t total_size. */ tpm_hash_extend(DRTM_LOC, DRTM_DATA_PCR, (uint8_t *)mbi, *mbi, DLE_EVTYPE_SLAUNCH, NULL, 0); From 19fa00a52ad5c2eea210f8c04dd1be30a9e5523b Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Thu, 21 Mar 2024 19:41:06 +0200 Subject: [PATCH 44/46] x86/boot: find MBI and SLRT on AMD secure-kernel-loader on AMD with SKINIT passes MBI as a parameter for Multiboot kernel. Another thing of interest is the location of SLRT which is bootloader's data after SKL. Signed-off-by: Sergii Dmytruk Signed-off-by: Krystian Hebel --- xen/arch/x86/boot/head.S | 35 ++++++++++++++++++---- xen/arch/x86/boot/slaunch_early.c | 48 +++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/xen/arch/x86/boot/head.S b/xen/arch/x86/boot/head.S index f593df9c9f..32ef12de89 100644 --- a/xen/arch/x86/boot/head.S +++ b/xen/arch/x86/boot/head.S @@ -353,10 +353,12 @@ cs32_switch: jmp *%edi /* - * Entry point for TrenchBoot Secure Launch on Intel TXT platforms. + * Entry point for TrenchBoot Secure Launch, common for Intel TXT and + * AMD Secure Startup, but state is slightly different. * + * On Intel: * CPU is in 32b protected mode with paging disabled. On entry: - * - %ebx = %eip = MLE entry point, + * - %ebx = %eip = this entry point, * - stack pointer is undefined, * - CS is flat 4GB code segment, * - DS, ES, SS, FS and GS are undefined according to TXT SDG, but this @@ -374,13 +376,34 @@ cs32_switch: * - trying to enter real mode results in reset * - APs must be brought up by MONITOR or GETSEC[WAKEUP], depending on * which is supported by a given SINIT ACM + * + * On AMD (as implemented by TrenchBoot's SKL): + * CPU is in 32b protected mode with paging disabled. On entry: + * - %ebx = %eip = this entry point, + * - %ebp holds base address of SKL + * - stack pointer is treated as undefined for parity with TXT, + * - CS is flat 4GB code segment, + * - DS, ES, SS are flat 4GB data segments, but treated as undefined for + * parity with TXT. + * + * Additional restrictions: + * - interrupts (including NMIs and SMIs) are disabled and must be + * enabled later + * - APs must be brought up by SIPI without an INIT */ slaunch_stub_entry: /* Calculate the load base address. */ mov %ebx, %esi sub $sym_offs(slaunch_stub_entry), %esi - /* Mark Secure Launch boot protocol and jump to common entry. */ + /* On AMD, %ebp holds the base address of SLB, save it for later. */ + mov %ebp, %ebx + + /* + * Mark Secure Launch boot protocol and jump to common entry. Note that + * all general purpose registers except %ebx and %esi are clobbered + * between here and .Lslaunch_proto. + */ mov $SLAUNCH_BOOTLOADER_MAGIC, %eax jmp .Lset_stack @@ -503,12 +526,14 @@ __start: sub $8, %esp push %esp /* pointer to output structure */ + push %ebx /* Slaunch parameter on AMD */ lea sym_offs(__2M_rwdata_end), %ecx /* end of target image */ lea sym_offs(_start), %edx /* target base address */ mov %esi, %eax /* load base address */ - /* slaunch_early_tests(load/eax, tgt/edx, tgt_end/ecx, ret/stk) using fastcall. */ + /* slaunch_early_tests(load/eax, tgt/edx, tgt_end/ecx, + slaunch/stk, ret/stk) using fastcall. */ call slaunch_early_tests - add $4, %esp + add $8, %esp /* Move outputs of slaunch_early_tests() from stack into registers. */ pop %eax /* physical MBI address */ diff --git a/xen/arch/x86/boot/slaunch_early.c b/xen/arch/x86/boot/slaunch_early.c index e818415a2d..5296fbe403 100644 --- a/xen/arch/x86/boot/slaunch_early.c +++ b/xen/arch/x86/boot/slaunch_early.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include struct early_tests_results { @@ -25,6 +27,21 @@ struct early_tests_results uint32_t slrt_pa; } __packed; +static bool is_intel_cpu(void) +{ + /* + * asm/processor.h can't be included in early code, which means neither + * cpuid() function nor boot_cpu_data can be used here. + */ + uint32_t eax, ebx, ecx, edx; + asm volatile ( "cpuid" + : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) + : "0" (0), "c" (0) ); + return ebx == X86_VENDOR_INTEL_EBX + && ecx == X86_VENDOR_INTEL_ECX + && edx == X86_VENDOR_INTEL_EDX; +} + static void verify_pmr_ranges(struct txt_os_mle_data *os_mle, struct txt_os_sinit_data *os_sinit, uint32_t load_base_addr, uint32_t tgt_base_addr, @@ -104,6 +121,7 @@ static void verify_pmr_ranges(struct txt_os_mle_data *os_mle, void slaunch_early_tests(uint32_t load_base_addr, uint32_t tgt_base_addr, uint32_t tgt_end_addr, + uint32_t slaunch_param, struct early_tests_results *result) { void *txt_heap; @@ -111,6 +129,36 @@ void slaunch_early_tests(uint32_t load_base_addr, struct txt_os_sinit_data *os_sinit; uint32_t size = tgt_end_addr - tgt_base_addr; + if ( !is_intel_cpu() ) + { + /* + * Not an Intel CPU. Currently the only other option is AMD with SKINIT + * and secure-kernel-loader. + */ + struct slr_table *slrt; + struct slr_entry_dl_info *dl_info; + + const uint16_t *sl_header = (void *)slaunch_param; + /* + * The fourth 16-bit integer of SKL's header is an offset to + * bootloader's data, which is SLRT. + */ + result->slrt_pa = slaunch_param + sl_header[3]; + slrt = (struct slr_table *)result->slrt_pa; + + result->mbi_pa = 0; + dl_info = (struct slr_entry_dl_info *) + slr_next_entry_by_tag (slrt, NULL, SLR_ENTRY_DL_INFO); + /* Basic checks only, SKL checked and consumed the rest. */ + if ( dl_info == NULL + || dl_info->hdr.size != sizeof(*dl_info) + || dl_info->bl_context.bootloader != SLR_BOOTLOADER_GRUB ) + return; + + result->mbi_pa = dl_info->bl_context.context; + return; + } + /* Clear the TXT error registers for a clean start of day */ write_txt_reg(TXTCR_ERRORCODE, 0); From 6657085cf33a2a19f688d198cc9d3b58d3d1b61d Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Fri, 22 Mar 2024 00:40:12 +0200 Subject: [PATCH 45/46] arch/x86: move generic memory mapping and protection to slaunch.c Signed-off-by: Sergii Dmytruk --- xen/arch/x86/include/asm/slaunch.h | 4 +++ xen/arch/x86/intel_txt.c | 24 ------------------ xen/arch/x86/setup.c | 11 +++++---- xen/arch/x86/slaunch.c | 39 ++++++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 29 deletions(-) diff --git a/xen/arch/x86/include/asm/slaunch.h b/xen/arch/x86/include/asm/slaunch.h index 70101bb5d6..1d81b0de02 100644 --- a/xen/arch/x86/include/asm/slaunch.h +++ b/xen/arch/x86/include/asm/slaunch.h @@ -40,6 +40,10 @@ static inline void find_evt_log(struct slr_table *slrt, void **evt_log, } } +void map_slaunch_mem_regions(void); + +void protect_slaunch_mem_regions(void); + /* * This helper function is used to map memory using L2 page tables by aligning * mapped regions to 2MB. This way page allocator (which at this point isn't diff --git a/xen/arch/x86/intel_txt.c b/xen/arch/x86/intel_txt.c index c3471dfe1f..cc9a6d01b0 100644 --- a/xen/arch/x86/intel_txt.c +++ b/xen/arch/x86/intel_txt.c @@ -15,11 +15,7 @@ static uint64_t __initdata txt_heap_base, txt_heap_size; void __init map_txt_mem_regions(void) { - void *evt_log_addr; - uint32_t evt_log_size; - map_l2(TXT_PRIV_CONFIG_REGS_BASE, NR_TXT_CONFIG_SIZE); - map_l2(TPM_TIS_BASE, TPM_TIS_SIZE); txt_heap_base = read_txt_reg(TXTCR_HEAP_BASE); BUG_ON(txt_heap_base == 0); @@ -28,20 +24,11 @@ void __init map_txt_mem_regions(void) BUG_ON(txt_heap_size == 0); map_l2(txt_heap_base, txt_heap_size); - - find_evt_log(__va(slaunch_slrt), &evt_log_addr, &evt_log_size); - map_l2((unsigned long)evt_log_addr, evt_log_size); - if ( evt_log_addr != NULL ) - map_l2((unsigned long)evt_log_addr, evt_log_size); } void __init protect_txt_mem_regions(void) { int rc; - - void *evt_log_addr; - uint32_t evt_log_size; - uint64_t sinit_base, sinit_size; /* TXT Heap */ @@ -52,17 +39,6 @@ void __init protect_txt_mem_regions(void) txt_heap_base + txt_heap_size); BUG_ON(rc == 0); - /* TXT TPM Event Log */ - find_evt_log(__va(slaunch_slrt), &evt_log_addr, &evt_log_size); - if ( evt_log_addr != NULL ) { - printk("SLAUNCH: reserving event log (%#lx - %#lx)\n", - (uint64_t)evt_log_addr, - (uint64_t)evt_log_addr + evt_log_size); - rc = reserve_e820_ram(&e820_raw, (uint64_t)evt_log_addr, - (uint64_t)evt_log_addr + evt_log_size); - BUG_ON(rc == 0); - } - sinit_base = read_txt_reg(TXTCR_SINIT_BASE); BUG_ON(sinit_base == 0); diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 27f77fd1c9..b59b754763 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -62,7 +62,6 @@ #include #include #include -#include #include #include @@ -1388,13 +1387,15 @@ void asmlinkage __init noreturn __start_xen(void) if ( slaunch_active ) { - /* Prepare for TXT-related code. */ - map_txt_mem_regions(); + /* Prepare for accesses to essential data structures setup by boot + * environment. */ + map_slaunch_mem_regions(); + /* Measure SLRT here because it gets used by init_e820(), the rest is * measured below by tpm_process_drtm_policy(). */ tpm_measure_slrt(); - /* Reserve TXT heap and SINIT. */ - protect_txt_mem_regions(); + + protect_slaunch_mem_regions(); } /* Sanitise the raw E820 map to produce a final clean version. */ diff --git a/xen/arch/x86/slaunch.c b/xen/arch/x86/slaunch.c index b4c3b2b851..e795e42547 100644 --- a/xen/arch/x86/slaunch.c +++ b/xen/arch/x86/slaunch.c @@ -1,4 +1,6 @@ #include +#include +#include #include #include #include @@ -35,6 +37,43 @@ int __init map_l2(unsigned long paddr, unsigned long size) pages, PAGE_HYPERVISOR); } +void __init map_slaunch_mem_regions(void) +{ + void *evt_log_addr; + uint32_t evt_log_size; + + map_l2(TPM_TIS_BASE, TPM_TIS_SIZE); + + /* Vendor-specific part. It may include contain slaunch_slrt. */ + map_txt_mem_regions(); + + find_evt_log(__va(slaunch_slrt), &evt_log_addr, &evt_log_size); + if ( evt_log_addr != NULL ) + map_l2((unsigned long)evt_log_addr, evt_log_size); +} + +void __init protect_slaunch_mem_regions(void) +{ + int rc; + + void *evt_log_addr; + uint32_t evt_log_size; + + find_evt_log(__va(slaunch_slrt), &evt_log_addr, &evt_log_size); + if ( evt_log_addr != NULL ) + { + printk("SLAUNCH: reserving event log (%#lx - %#lx)\n", + (uint64_t)evt_log_addr, + (uint64_t)evt_log_addr + evt_log_size); + rc = reserve_e820_ram(&e820_raw, (uint64_t)evt_log_addr, + (uint64_t)evt_log_addr + evt_log_size); + BUG_ON(rc == 0); + } + + /* Vendor-specific part. */ + protect_txt_mem_regions(); +} + static struct slr_table *slr_get_table(void) { struct slr_table *slrt = __va(slaunch_slrt); From afd6b78b7c16034858bd5575b195b429c2dea717 Mon Sep 17 00:00:00 2001 From: Sergii Dmytruk Date: Sun, 17 Mar 2024 00:58:26 +0200 Subject: [PATCH 46/46] arch/x86: support slaunch with AMD SKINIT This mostly involves not running Intel-specific code when on AMD. There are only a few new AMD-specific implementation details: - finding SLB start and size and then mapping and protecting it - managing offset for adding the next TPM log entry (TXT-compatible data prepared by SKL is stored inside of vendor data field of TCG header) Signed-off-by: Sergii Dmytruk Signed-off-by: Krystian Hebel --- xen/arch/x86/e820.c | 2 +- xen/arch/x86/include/asm/slaunch.h | 2 + xen/arch/x86/slaunch.c | 68 ++++++++++++++++++++++++------ xen/arch/x86/tpm.c | 66 ++++++++++++++++++++++++++++- 4 files changed, 122 insertions(+), 16 deletions(-) diff --git a/xen/arch/x86/e820.c b/xen/arch/x86/e820.c index 3892f901b5..5241f2bb58 100644 --- a/xen/arch/x86/e820.c +++ b/xen/arch/x86/e820.c @@ -457,7 +457,7 @@ static uint64_t __init mtrr_top_of_ram(void) rdmsrl(MSR_MTRRcap, mtrr_cap); rdmsrl(MSR_MTRRdefType, mtrr_def); - if ( slaunch_active ) + if ( slaunch_active && boot_cpu_data.x86_vendor == X86_VENDOR_INTEL ) txt_restore_mtrrs(e820_verbose); if ( e820_verbose ) diff --git a/xen/arch/x86/include/asm/slaunch.h b/xen/arch/x86/include/asm/slaunch.h index 1d81b0de02..b8a73a5ea6 100644 --- a/xen/arch/x86/include/asm/slaunch.h +++ b/xen/arch/x86/include/asm/slaunch.h @@ -11,6 +11,8 @@ /* * Secure Launch event log entry types. The TXT specification defines the * base event value as 0x400 for DRTM values. + * + * Using the same values for AMD SKINIT. */ #define TXT_EVTYPE_BASE 0x400 #define DLE_EVTYPE_SLAUNCH (TXT_EVTYPE_BASE + 0x102) diff --git a/xen/arch/x86/slaunch.c b/xen/arch/x86/slaunch.c index e795e42547..393c1a25b5 100644 --- a/xen/arch/x86/slaunch.c +++ b/xen/arch/x86/slaunch.c @@ -9,6 +9,10 @@ #include #include +/* SLB is 64k, 64k-aligned */ +#define SKINIT_SLB_SIZE 0x10000 +#define SKINIT_SLB_ALIGN 0x10000 + bool __initdata slaunch_active; uint32_t __initdata slaunch_slrt; @@ -37,6 +41,19 @@ int __init map_l2(unsigned long paddr, unsigned long size) pages, PAGE_HYPERVISOR); } +static uint32_t get_slb_start(void) +{ + /* The runtime computation relies on size being a power of 2 and equal to + * alignment. Make sure these assumptions hold. */ + BUILD_BUG_ON(SKINIT_SLB_SIZE != SKINIT_SLB_ALIGN); + BUILD_BUG_ON(SKINIT_SLB_SIZE == 0); + BUILD_BUG_ON((SKINIT_SLB_SIZE & (SKINIT_SLB_SIZE - 1)) != 0); + + /* Rounding any address within SLB down to alignment gives SLB base and + * SLRT is inside SLB on AMD. */ + return slaunch_slrt & ~(SKINIT_SLB_SIZE - 1); +} + void __init map_slaunch_mem_regions(void) { void *evt_log_addr; @@ -45,7 +62,14 @@ void __init map_slaunch_mem_regions(void) map_l2(TPM_TIS_BASE, TPM_TIS_SIZE); /* Vendor-specific part. It may include contain slaunch_slrt. */ - map_txt_mem_regions(); + if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL ) + { + map_txt_mem_regions(); + } + else if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD ) + { + map_l2(get_slb_start(), SKINIT_SLB_SIZE); + } find_evt_log(__va(slaunch_slrt), &evt_log_addr, &evt_log_size); if ( evt_log_addr != NULL ) @@ -71,11 +95,25 @@ void __init protect_slaunch_mem_regions(void) } /* Vendor-specific part. */ - protect_txt_mem_regions(); + if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL ) + { + protect_txt_mem_regions(); + } + else if ( boot_cpu_data.x86_vendor == X86_VENDOR_AMD ) + { + uint64_t slb_start = get_slb_start(); + uint64_t slb_end = slb_start + SKINIT_SLB_SIZE; + printk("SLAUNCH: reserving SLB (%#lx - %#lx)\n", slb_start, slb_end); + e820_change_range_type(&e820_raw, slb_start, slb_end, + E820_RAM, E820_RESERVED); + } } static struct slr_table *slr_get_table(void) { + bool intel_cpu = (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL); + uint16_t slrt_architecture = intel_cpu ? SLR_INTEL_TXT : SLR_AMD_SKINIT; + struct slr_table *slrt = __va(slaunch_slrt); map_l2(slaunch_slrt, PAGE_SIZE); @@ -85,9 +123,9 @@ static struct slr_table *slr_get_table(void) /* XXX: are newer revisions allowed? */ if ( slrt->revision != SLR_TABLE_REVISION ) panic("SLRT is of unsupported revision: %#04x!\n", slrt->revision); - if ( slrt->architecture != SLR_INTEL_TXT ) - panic("SLRT is for unexpected architecture: %#04x!\n", - slrt->architecture); + if ( slrt->architecture != slrt_architecture ) + panic("SLRT is for unexpected architecture: %#04x != %#04x!\n", + slrt->architecture, slrt_architecture); if ( slrt->size > slrt->max_size ) panic("SLRT is larger than its max size: %#08x > %#08x!\n", slrt->size, slrt->max_size); @@ -104,14 +142,18 @@ void tpm_measure_slrt(void) if ( slrt->revision == 1 ) { - /* In revision one of the SLRT, only Intel info table is measured. */ - struct slr_entry_intel_info *intel_info = - (void *)slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_INTEL_INFO); - if ( intel_info == NULL ) - panic("SLRT is missing Intel-specific information!\n"); - - tpm_hash_extend(DRTM_LOC, DRTM_DATA_PCR, (uint8_t *)intel_info, - sizeof(*intel_info), DLE_EVTYPE_SLAUNCH, NULL, 0); + if ( boot_cpu_data.x86_vendor == X86_VENDOR_INTEL ) + { + /* In revision one of the SLRT, only Intel info table is + * measured. */ + struct slr_entry_intel_info *intel_info = + (void *)slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_INTEL_INFO); + if ( intel_info == NULL ) + panic("SLRT is missing Intel-specific information!\n"); + + tpm_hash_extend(DRTM_LOC, DRTM_DATA_PCR, (uint8_t *)intel_info, + sizeof(*intel_info), DLE_EVTYPE_SLAUNCH, NULL, 0); + } } else { diff --git a/xen/arch/x86/tpm.c b/xen/arch/x86/tpm.c index 6596a72379..c7d5bd23ce 100644 --- a/xen/arch/x86/tpm.c +++ b/xen/arch/x86/tpm.c @@ -21,6 +21,7 @@ #include #include #include +#include #ifdef __EARLY_TPM__ @@ -57,11 +58,31 @@ void *memcpy(void *dest, const void *src, size_t n) return dest; } +static bool is_amd_cpu(void) +{ + /* + * asm/processor.h can't be included in early code, which means neither + * cpuid() function nor boot_cpu_data can be used here. + */ + uint32_t eax, ebx, ecx, edx; + asm volatile ( "cpuid" + : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) + : "0" (0), "c" (0) ); + return ebx == X86_VENDOR_AMD_EBX + && ecx == X86_VENDOR_AMD_ECX + && edx == X86_VENDOR_AMD_EDX; +} + #else /* __EARLY_TPM__ */ #include #include +static bool is_amd_cpu(void) +{ + return boot_cpu_data.x86_vendor == X86_VENDOR_AMD; +} + #endif /* __EARLY_TPM__ */ #define TPM_LOC_REG(loc, reg) (0x1000 * (loc) + (reg)) @@ -247,6 +268,21 @@ struct TPM12_PCREvent { uint8_t Data[]; }; +struct tpm1_spec_id_event { + uint32_t pcrIndex; + uint32_t eventType; + uint8_t digest[20]; + uint32_t eventSize; + uint8_t signature[16]; + uint32_t platformClass; + uint8_t specVersionMinor; + uint8_t specVersionMajor; + uint8_t specErrata; + uint8_t uintnSize; + uint8_t vendorInfoSize; + uint8_t vendorInfo[0]; /* variable number of members */ +} __packed; + struct txt_ev_log_container_12 { char Signature[20]; /* "TXT Event Container", null-terminated */ uint8_t Reserved[12]; @@ -389,6 +425,15 @@ static void *create_log_event12(struct txt_ev_log_container_12 *evt_log, { struct TPM12_PCREvent *new_entry; + if ( is_amd_cpu() ) { + /* + * On AMD, TXT-compatible structure is stored as vendor data of + * TCG-defined event log header. + */ + struct tpm1_spec_id_event *spec_id = (void *)evt_log; + evt_log = (struct txt_ev_log_container_12 *)&spec_id->vendorInfo[0]; + } + new_entry = (void *)(((uint8_t *)evt_log) + evt_log->NextEventOffset); /* @@ -824,11 +869,28 @@ static uint32_t tpm2_hash_extend(unsigned loc, uint8_t *buf, unsigned size, #endif /* __EARLY_TPM__ */ -static struct heap_event_log_pointer_element2_1 *find_evt_log_ext_data(void) +static struct heap_event_log_pointer_element2_1 * +find_evt_log_ext_data(struct tpm2_spec_id_event *evt_log) { struct txt_os_sinit_data *os_sinit; struct txt_ext_data_element *ext_data; + if ( is_amd_cpu() ) { + /* + * Event log pointer is defined by TXT specification, but + * secure-kernel-loader provides a compatible structure in vendor data + * of the log. + */ + const uint8_t *data_size = + (void *)&evt_log->digestSizes[evt_log->digestCount]; + + if ( *data_size != sizeof(struct heap_event_log_pointer_element2_1) ) + return NULL; + + /* Vendor data directly follows one-byte size. */ + return (void *)(data_size + 1); + } + os_sinit = txt_os_sinit_data_start(__va(read_txt_reg(TXTCR_HEAP_BASE))); ext_data = (void *)((uint8_t *)os_sinit + sizeof(*os_sinit)); @@ -861,7 +923,7 @@ create_log_event20(struct tpm2_spec_id_event *evt_log, uint32_t evt_log_size, unsigned i; uint8_t *p; - log_ext_data = find_evt_log_ext_data(); + log_ext_data = find_evt_log_ext_data(evt_log); if ( log_ext_data == NULL ) return log_hashes;