From 413d4c8714316e9656acca661962ceaedc44afd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20=C5=BByjewski?= Date: Mon, 13 May 2024 00:27:33 +0300 Subject: [PATCH] Add patches for TrenchBoot DRTM support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tomasz Żyjewski Signed-off-by: Sergii Dmytruk --- ...intel_txt.h-constants-and-accessors-.patch | 339 ++++++++ ...t-add-MLE-header-and-new-entry-point.patch | 108 +++ ...ly-add-early-TXT-tests-and-restore-M.patch | 305 ++++++++ ...table.h-Secure-Launch-Resource-Table.patch | 283 +++++++ 1304-xen-arch-x86-reserve-TXT-memory.patch | 240 ++++++ 1305-x86-intel_txt.c-restore-boot-MTRRs.patch | 120 +++ 1306-lib-sha1.c-add-file.patch | 308 ++++++++ ...or-early-hashing-and-extending-PCRs-.patch | 657 ++++++++++++++++ ...oot-choose-AP-stack-based-on-APIC-ID.patch | 166 ++++ 1309-x86-smpboot.c-TXT-AP-bringup.patch | 217 ++++++ ...ccess-x86_cpu_to_apicid-directly-use.patch | 265 +++++++ ...p-x86_cpu_to_apicid-use-cpu_data-cpu.patch | 156 ++++ ...-x86-smp-move-stack_base-to-cpu_data.patch | 222 ++++++ ...x86-smp-call-x2apic_ap_setup-earlier.patch | 48 ++ ...n-protect-against-recurrent-machine_.patch | 54 ++ ...ch-x86-smp-drop-booting_cpu-variable.patch | 121 +++ ...-arch-x86-smp-make-cpu_state-per-CPU.patch | 219 ++++++ ...ove-MONITOR-MWAIT-loop-for-TXT-AP-br.patch | 80 ++ ...-t-send-INIT-SIPI-SIPI-if-AP-is-alre.patch | 82 ++ ...mp-start-APs-in-parallel-during-boot.patch | 128 +++ 1320-lib-sha256.c-add-file.patch | 305 ++++++++ ...m.c-support-extending-PCRs-of-TPM2.0.patch | 523 +++++++++++++ ...tpm.c-implement-event-log-for-TPM2.0.patch | 257 ++++++ 1323-arch-x86-process-DRTM-policy.patch | 282 +++++++ 1324-arch-x86-extract-slaunch-unit.patch | 731 ++++++++++++++++++ ...troduce-slaunch_slrt-global-variable.patch | 283 +++++++ 1326-x86-boot-find-MBI-and-SLRT-on-AMD.patch | 124 +++ ...neric-memory-mapping-and-protection-.patch | 174 +++++ ...-x86-support-slaunch-with-AMD-SKINIT.patch | 289 +++++++ xen.spec.in | 31 + 30 files changed, 7117 insertions(+) create mode 100644 1300-x86-include-asm-intel_txt.h-constants-and-accessors-.patch create mode 100644 1301-x86-boot-add-MLE-header-and-new-entry-point.patch create mode 100644 1302-x86-boot-txt_early-add-early-TXT-tests-and-restore-M.patch create mode 100644 1303-include-xen-slr_table.h-Secure-Launch-Resource-Table.patch create mode 100644 1304-xen-arch-x86-reserve-TXT-memory.patch create mode 100644 1305-x86-intel_txt.c-restore-boot-MTRRs.patch create mode 100644 1306-lib-sha1.c-add-file.patch create mode 100644 1307-x86-tpm.c-code-for-early-hashing-and-extending-PCRs-.patch create mode 100644 1308-x86-boot-choose-AP-stack-based-on-APIC-ID.patch create mode 100644 1309-x86-smpboot.c-TXT-AP-bringup.patch create mode 100644 1310-arch-x86-don-t-access-x86_cpu_to_apicid-directly-use.patch create mode 100644 1311-arch-x86-smp-drop-x86_cpu_to_apicid-use-cpu_data-cpu.patch create mode 100644 1312-arch-x86-smp-move-stack_base-to-cpu_data.patch create mode 100644 1313-arch-x86-smp-call-x2apic_ap_setup-earlier.patch create mode 100644 1314-arch-x86-shutdown-protect-against-recurrent-machine_.patch create mode 100644 1315-arch-x86-smp-drop-booting_cpu-variable.patch create mode 100644 1316-arch-x86-smp-make-cpu_state-per-CPU.patch create mode 100644 1317-arch-x86-smp-remove-MONITOR-MWAIT-loop-for-TXT-AP-br.patch create mode 100644 1318-arch-x86-smp-don-t-send-INIT-SIPI-SIPI-if-AP-is-alre.patch create mode 100644 1319-arch-x86-smp-start-APs-in-parallel-during-boot.patch create mode 100644 1320-lib-sha256.c-add-file.patch create mode 100644 1321-x86-tpm.c-support-extending-PCRs-of-TPM2.0.patch create mode 100644 1322-x86-tpm.c-implement-event-log-for-TPM2.0.patch create mode 100644 1323-arch-x86-process-DRTM-policy.patch create mode 100644 1324-arch-x86-extract-slaunch-unit.patch create mode 100644 1325-x86-boot-introduce-slaunch_slrt-global-variable.patch create mode 100644 1326-x86-boot-find-MBI-and-SLRT-on-AMD.patch create mode 100644 1327-arch-x86-move-generic-memory-mapping-and-protection-.patch create mode 100644 1328-arch-x86-support-slaunch-with-AMD-SKINIT.patch diff --git a/1300-x86-include-asm-intel_txt.h-constants-and-accessors-.patch b/1300-x86-include-asm-intel_txt.h-constants-and-accessors-.patch new file mode 100644 index 0000000..2ef46d9 --- /dev/null +++ b/1300-x86-include-asm-intel_txt.h-constants-and-accessors-.patch @@ -0,0 +1,339 @@ +From 3a32ed82780392fabd68ef8421f750579cbf457a Mon Sep 17 00:00:00 2001 +From: Krystian Hebel +Date: Mon, 17 Apr 2023 20:10:13 +0200 +Subject: [PATCH 1300/1328] 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 | 267 +++++++++++++++++++++++++++ + xen/arch/x86/tboot.c | 20 +- + 2 files changed, 269 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..865161cf93 +--- /dev/null ++++ b/xen/arch/x86/include/asm/intel_txt.h +@@ -0,0 +1,267 @@ ++/* ++ * 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 __BOOT_DEFS_H__ ++#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 a2e9e97ed7..ffd1126dfc 100644 +--- a/xen/arch/x86/tboot.c ++++ b/xen/arch/x86/tboot.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + + /* tboot= */ +@@ -31,23 +32,6 @@ static vmac_t frametable_mac; /* MAC for frame table during S3 */ + static uint64_t __initdata txt_heap_base, __initdata txt_heap_size; + static uint64_t __initdata sinit_base, __initdata sinit_size; + +-/* +- * 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]; + +@@ -452,7 +436,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; +-- +2.46.0 + diff --git a/1301-x86-boot-add-MLE-header-and-new-entry-point.patch b/1301-x86-boot-add-MLE-header-and-new-entry-point.patch new file mode 100644 index 0000000..67d5664 --- /dev/null +++ b/1301-x86-boot-add-MLE-header-and-new-entry-point.patch @@ -0,0 +1,108 @@ +From aa2c99c6b62661866cc823b9f4c78bd1bd6cce43 Mon Sep 17 00:00:00 2001 +From: Kacper Stojek +Date: Wed, 31 Aug 2022 15:03:51 +0200 +Subject: [PATCH 1301/1328] 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 | 45 +++++++++++++++++++++ + 2 files changed, 50 insertions(+) + +diff --git a/docs/hypervisor-guide/x86/how-xen-boots.rst b/docs/hypervisor-guide/x86/how-xen-boots.rst +index ca77d7c8a3..eb60a1cd80 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 6bc64c9e86..1f7ce5f6ae 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 +@@ -114,6 +115,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!" +@@ -433,6 +453,31 @@ __pvh_start: + + #endif /* CONFIG_PVH_GUEST */ + ++ /* ++ * Entry point for TrenchBoot Secure Launch on Intel TXT platforms. ++ * ++ * CPU is in 32b protected mode with paging disabled. On entry: ++ * - %ebx = %ebp = SINIT physical base address ++ * - %edx = SENTER control flags ++ * - stack pointer is undefined ++ * - CS is flat 4GB code segment ++ * - DS, ES and SS are flat 4GB data segments ++ * ++ * 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: ++ movl $SLAUNCH_BOOTLOADER_MAGIC,%eax ++ ++ /* Fall through to Multiboot entry point. */ ++ + __start: + cld + cli +-- +2.46.0 + diff --git a/1302-x86-boot-txt_early-add-early-TXT-tests-and-restore-M.patch b/1302-x86-boot-txt_early-add-early-TXT-tests-and-restore-M.patch new file mode 100644 index 0000000..44b7569 --- /dev/null +++ b/1302-x86-boot-txt_early-add-early-TXT-tests-and-restore-M.patch @@ -0,0 +1,305 @@ +From 37d1ca20da76cfa0fc6ef1954731c41e60da674e Mon Sep 17 00:00:00 2001 +From: Krystian Hebel +Date: Mon, 17 Apr 2023 20:09:54 +0200 +Subject: [PATCH 1302/1328] 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 | 2 +- + xen/arch/x86/boot/head.S | 25 +++++ + xen/arch/x86/boot/txt_early.c | 132 +++++++++++++++++++++++++++ + xen/arch/x86/include/asm/intel_txt.h | 28 ++++++ + xen/arch/x86/intel_txt.c | 11 +++ + 6 files changed, 198 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 3e43fcaea9..e62b9ff9bc 100644 +--- a/xen/arch/x86/Makefile ++++ b/xen/arch/x86/Makefile +@@ -57,6 +57,7 @@ obj-y += percpu.o + obj-y += physdev.o + obj-$(CONFIG_COMPAT) += x86_64/physdev.o + obj-y += 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 d6bc8fc084..34df17664a 100644 +--- a/xen/arch/x86/boot/Makefile ++++ b/xen/arch/x86/boot/Makefile +@@ -1,6 +1,6 @@ + obj-bin-y += head.o + +-head-bin-objs := cmdline.o reloc.o ++head-bin-objs := cmdline.o reloc.o txt_early.o + + nocov-y += $(head-bin-objs) + noubsan-y += $(head-bin-objs) +diff --git a/xen/arch/x86/boot/head.S b/xen/arch/x86/boot/head.S +index 1f7ce5f6ae..6d8988f53c 100644 +--- a/xen/arch/x86/boot/head.S ++++ b/xen/arch/x86/boot/head.S +@@ -506,6 +506,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 +@@ -521,6 +525,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) ++ ++ /* Push arguments to stack and call txt_early_tests(). */ ++ push $sym_offs(__2M_rwdata_end) /* end of target image */ ++ push $sym_offs(_start) /* target base address */ ++ push %esi /* load base address */ ++ 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 +@@ -851,6 +872,10 @@ cmdline_parse_early: + reloc: + .incbin "reloc.bin" + ++ ALIGN ++txt_early_tests: ++ .incbin "txt_early.bin" ++ + ENTRY(trampoline_start) + #include "trampoline.S" + ENTRY(trampoline_end) +diff --git a/xen/arch/x86/boot/txt_early.c b/xen/arch/x86/boot/txt_early.c +new file mode 100644 +index 0000000000..23ee734c47 +--- /dev/null ++++ b/xen/arch/x86/boot/txt_early.c +@@ -0,0 +1,132 @@ ++/* ++ * Copyright (c) 2022-2023 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 . ++ */ ++ ++/* ++ * This entry point is entered from xen/arch/x86/boot/head.S with Xen base at ++ * 0x4(%esp). A pointer to MBI is returned in %eax. ++ */ ++asm ( ++ " .text \n" ++ " .globl _start \n" ++ "_start: \n" ++ " jmp txt_early_tests \n" ++ ); ++ ++#include "defs.h" ++#include "../include/asm/intel_txt.h" ++ ++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 __stdcall 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 865161cf93..696ed92bac 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 __BOOT_DEFS_H__ + #define _txt(x) _p(x) +@@ -264,4 +266,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); ++} +-- +2.46.0 + diff --git a/1303-include-xen-slr_table.h-Secure-Launch-Resource-Table.patch b/1303-include-xen-slr_table.h-Secure-Launch-Resource-Table.patch new file mode 100644 index 0000000..6f856bb --- /dev/null +++ b/1303-include-xen-slr_table.h-Secure-Launch-Resource-Table.patch @@ -0,0 +1,283 @@ +From bbbd77a2758ebf4765c03a50176d52eafc6a5661 Mon Sep 17 00:00:00 2001 +From: Sergii Dmytruk +Date: Sun, 29 Oct 2023 00:29:30 +0300 +Subject: [PATCH 1303/1328] 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 | 255 ++++++++++++++++++++++++++++++++++++ + 1 file changed, 255 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..21ca78baa6 +--- /dev/null ++++ b/xen/include/xen/slr_table.h +@@ -0,0 +1,255 @@ ++/* 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 ++{ ++ uint16_t tag; ++ uint16_t size; ++} __packed; ++ ++/* ++ * Boot loader context ++ */ ++struct slr_bl_context ++{ ++ uint16_t bootloader; ++ uint16_t reserved; ++ uint64_t context; ++} __packed; ++ ++/* ++ * DRTM Dynamic Launch Configuration ++ */ ++struct slr_entry_dl_info ++{ ++ struct slr_entry_hdr hdr; ++ struct slr_bl_context bl_context; ++ uint64_t dl_handler; ++ uint64_t dce_base; ++ uint32_t dce_size; ++ uint64_t dlme_entry; ++} __packed; ++ ++/* ++ * TPM Log Information ++ */ ++struct slr_entry_log_info ++{ ++ struct slr_entry_hdr hdr; ++ uint16_t format; ++ uint16_t reserved; ++ uint64_t addr; ++ uint32_t size; ++} __packed; ++ ++/* ++ * DRTM Measurement Policy ++ */ ++struct slr_entry_policy ++{ ++ struct slr_entry_hdr hdr; ++ uint16_t revision; ++ uint16_t nr_entries; ++ /* policy_entries[] */ ++} __packed; ++ ++/* ++ * DRTM Measurement Entry ++ */ ++struct slr_policy_entry ++{ ++ uint16_t pcr; ++ uint16_t entity_type; ++ uint16_t flags; ++ uint16_t reserved; ++ uint64_t entity; ++ uint64_t size; ++ char evt_info[TPM_EVENT_INFO_LENGTH]; ++} __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 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; ++ ++struct slr_entry_uefi_config ++{ ++ struct slr_entry_hdr hdr; ++ uint16_t revision; ++ uint16_t nr_entries; ++ /* uefi_cfg_entries[] */ ++} __packed; ++ ++struct slr_uefi_cfg_entry ++{ ++ uint16_t pcr; ++ uint16_t reserved; ++ uint64_t cfg; /* address or value */ ++ uint32_t size; ++ char evt_info[TPM_EVENT_INFO_LENGTH]; ++} __packed; ++ ++static inline void * ++slr_end_of_entries(struct slr_table *table) ++{ ++ return (void *)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 *) ++ ((void *)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 *)((void *)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 */ +-- +2.46.0 + diff --git a/1304-xen-arch-x86-reserve-TXT-memory.patch b/1304-xen-arch-x86-reserve-TXT-memory.patch new file mode 100644 index 0000000..bb6fdd4 --- /dev/null +++ b/1304-xen-arch-x86-reserve-TXT-memory.patch @@ -0,0 +1,240 @@ +From e600644d247fc44d392bf27b1e51a0e7d3ba4de5 Mon Sep 17 00:00:00 2001 +From: Kacper Stojek +Date: Fri, 2 Sep 2022 08:11:43 +0200 +Subject: [PATCH 1304/1328] 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 696ed92bac..cc0ab5ac53 100644 +--- a/xen/arch/x86/include/asm/intel_txt.h ++++ b/xen/arch/x86/include/asm/intel_txt.h +@@ -88,6 +88,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. +@@ -292,4 +294,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 5845b729c3..99ed61f54e 100644 +--- a/xen/arch/x86/include/asm/mm.h ++++ b/xen/arch/x86/include/asm/mm.h +@@ -98,6 +98,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 d47f156711..06e5dec254 100644 +--- a/xen/arch/x86/setup.c ++++ b/xen/arch/x86/setup.c +@@ -55,6 +55,7 @@ + #include + #include + #include ++#include + + /* opt_nosmp: If true, secondary processors are ignored. */ + static bool __initdata opt_nosmp; +@@ -849,9 +850,6 @@ static struct domain *__init create_dom0(const module_t *image, + return d; + } + +-/* How much of the directmap is prebuilt at compile time. */ +-#define PREBUILT_MAP_LIMIT (1 << L2_PAGETABLE_SHIFT) +- + void __init noreturn __start_xen(unsigned long mbi_p) + { + char *memmap_type = NULL; +@@ -1170,6 +1168,14 @@ void __init noreturn __start_xen(unsigned long mbi_p) + #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); + +-- +2.46.0 + diff --git a/1305-x86-intel_txt.c-restore-boot-MTRRs.patch b/1305-x86-intel_txt.c-restore-boot-MTRRs.patch new file mode 100644 index 0000000..375e402 --- /dev/null +++ b/1305-x86-intel_txt.c-restore-boot-MTRRs.patch @@ -0,0 +1,120 @@ +From 15e8a7295f605bc752ba8686b2b27802a8381f7b Mon Sep 17 00:00:00 2001 +From: Krystian Hebel +Date: Wed, 19 Oct 2022 19:52:24 +0200 +Subject: [PATCH 1305/1328] 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 c5911cf48d..f836fec189 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 cc0ab5ac53..2b528977e9 100644 +--- a/xen/arch/x86/include/asm/intel_txt.h ++++ b/xen/arch/x86/include/asm/intel_txt.h +@@ -333,5 +333,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(). */ ++} +-- +2.46.0 + diff --git a/1306-lib-sha1.c-add-file.patch b/1306-lib-sha1.c-add-file.patch new file mode 100644 index 0000000..0115575 --- /dev/null +++ b/1306-lib-sha1.c-add-file.patch @@ -0,0 +1,308 @@ +From 2ec50d9686083882f27e088270a1c9747f708d8f Mon Sep 17 00:00:00 2001 +From: Krystian Hebel +Date: Tue, 25 Oct 2022 16:04:17 +0200 +Subject: [PATCH 1306/1328] 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 +--- + 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 b311ea739c..3820e0bfbb 100644 +--- a/xen/lib/Makefile ++++ b/xen/lib/Makefile +@@ -28,6 +28,7 @@ lib-y += strrchr.o + lib-y += strsep.o + lib-y += strspn.o + lib-y += strstr.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..ea4f5bf1c8 +--- /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 __u32 *)&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((__u32 *)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 { \ ++ __u32 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 { ++ u32 state[SHA1_DIGEST_SIZE / 4]; ++ u64 count; ++ u8 buffer[SHA1_BLOCK_SIZE]; ++}; ++ ++typedef void sha1_block_fn(struct sha1_state *sst, const u8 *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(__u32 *digest, const u8 *data, __u32 *array) ++{ ++ __u32 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 u8 *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, u8 *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 u8 *src, ++ int blocks) ++{ ++ u32 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 u8 *data, unsigned int len, u8 *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); ++} +-- +2.46.0 + diff --git a/1307-x86-tpm.c-code-for-early-hashing-and-extending-PCRs-.patch b/1307-x86-tpm.c-code-for-early-hashing-and-extending-PCRs-.patch new file mode 100644 index 0000000..1235943 --- /dev/null +++ b/1307-x86-tpm.c-code-for-early-hashing-and-extending-PCRs-.patch @@ -0,0 +1,657 @@ +From abc7f9edb4efac004bbbc212213ec0e79e576f59 Mon Sep 17 00:00:00 2001 +From: Krystian Hebel +Date: Fri, 21 Oct 2022 18:46:33 +0200 +Subject: [PATCH 1307/1328] 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 | 6 +- + xen/arch/x86/boot/head.S | 12 +- + 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 | 446 +++++++++++++++++++++++++++ + 7 files changed, 502 insertions(+), 11 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 e62b9ff9bc..d967aabf29 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-y += tsx.o + obj-y += usercopy.o +diff --git a/xen/arch/x86/boot/Makefile b/xen/arch/x86/boot/Makefile +index 34df17664a..913fa9d2c6 100644 +--- a/xen/arch/x86/boot/Makefile ++++ b/xen/arch/x86/boot/Makefile +@@ -1,6 +1,6 @@ + obj-bin-y += head.o + +-head-bin-objs := cmdline.o reloc.o txt_early.o ++head-bin-objs := cmdline.o reloc.o txt_early.o tpm_early.o + + nocov-y += $(head-bin-objs) + noubsan-y += $(head-bin-objs) +@@ -29,6 +29,10 @@ LDFLAGS_DIRECT += $(LDFLAGS_DIRECT-y) + %.bin: %.lnk + $(OBJCOPY) -j .text -O binary $< $@ + ++$(obj)/tpm_early.o: XEN_CFLAGS += -D__EARLY_TPM__ ++$(obj)/tpm_early.o: $(src)/../tpm.c FORCE ++ $(call if_changed_rule,cc_o_c) ++ + %.lnk: %.o $(src)/build32.lds + $(LD) $(subst x86_64,i386,$(LDFLAGS_DIRECT)) -N -T $(filter %.lds,$^) -o $@ $< + +diff --git a/xen/arch/x86/boot/head.S b/xen/arch/x86/boot/head.S +index 6d8988f53c..33c0779368 100644 +--- a/xen/arch/x86/boot/head.S ++++ b/xen/arch/x86/boot/head.S +@@ -536,10 +536,14 @@ __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. + */ ++ push %eax + 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: +@@ -876,6 +880,10 @@ reloc: + txt_early_tests: + .incbin "txt_early.bin" + ++ ALIGN ++tpm_extend_mbi: ++ .incbin "tpm_early.bin" ++ + ENTRY(trampoline_start) + #include "trampoline.S" + ENTRY(trampoline_end) +diff --git a/xen/arch/x86/include/asm/intel_txt.h b/xen/arch/x86/include/asm/intel_txt.h +index 2b528977e9..8505f37210 100644 +--- a/xen/arch/x86/include/asm/intel_txt.h ++++ b/xen/arch/x86/include/asm/intel_txt.h +@@ -308,15 +308,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 ) +@@ -331,8 +327,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..1bd271dbe2 +--- /dev/null ++++ b/xen/arch/x86/tpm.c +@@ -0,0 +1,446 @@ ++/* ++ * Copyright (c) 2022 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 . ++ */ ++ ++#ifdef __EARLY_TPM__ ++/* ++ * This entry point is entered from xen/arch/x86/boot/head.S with MBI base at ++ * 0x4(%esp). ++ */ ++asm ( ++ " .text \n" ++ " .globl _start \n" ++ "_start: \n" ++ " jmp tpm_extend_mbi \n" ++ ); ++ ++#include "boot/defs.h" ++#include "include/asm/intel_txt.h" ++#include "include/asm/tpm.h" ++#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 ++#include ++#include ++#include ++ ++#endif /* __EARLY_TPM__ */ ++ ++#include ++ ++#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(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 __stdcall 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 +-- +2.46.0 + diff --git a/1308-x86-boot-choose-AP-stack-based-on-APIC-ID.patch b/1308-x86-boot-choose-AP-stack-based-on-APIC-ID.patch new file mode 100644 index 0000000..1c54c05 --- /dev/null +++ b/1308-x86-boot-choose-AP-stack-based-on-APIC-ID.patch @@ -0,0 +1,166 @@ +From d71e552eb4eea07c92d028dda0084bdb63dfed51 Mon Sep 17 00:00:00 2001 +From: Krystian Hebel +Date: Wed, 16 Nov 2022 15:03:07 +0100 +Subject: [PATCH 1308/1328] 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 33c0779368..7ea50f0098 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 cdecf949b4..6440f31568 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 5d12937a0e..ad2f5058f0 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 2440d83c8d..251d7f5465 100644 +--- a/xen/arch/x86/include/asm/apicdef.h ++++ b/xen/arch/x86/include/asm/apicdef.h +@@ -129,6 +129,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 b9e878f8c7..57025b9bf7 100644 +--- a/xen/arch/x86/include/asm/msr-index.h ++++ b/xen/arch/x86/include/asm/msr-index.h +@@ -165,6 +165,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 06e5dec254..49694e10a2 100644 +--- a/xen/arch/x86/setup.c ++++ b/xen/arch/x86/setup.c +@@ -1907,6 +1907,7 @@ void __init noreturn __start_xen(unsigned long mbi_p) + */ + if ( !pv_shim ) + { ++ /* Separate loop to make parallel AP bringup possible. */ + for_each_present_cpu ( i ) + { + /* Set up cpu_to_node[]. */ +@@ -1914,6 +1915,12 @@ void __init noreturn __start_xen(unsigned long mbi_p) + /* 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) ) + { +-- +2.46.0 + diff --git a/1309-x86-smpboot.c-TXT-AP-bringup.patch b/1309-x86-smpboot.c-TXT-AP-bringup.patch new file mode 100644 index 0000000..13b7168 --- /dev/null +++ b/1309-x86-smpboot.c-TXT-AP-bringup.patch @@ -0,0 +1,217 @@ +From e98ee2d437797e7c2ba67c5e65850dc8d3118884 Mon Sep 17 00:00:00 2001 +From: Krystian Hebel +Date: Wed, 16 Nov 2022 15:06:18 +0100 +Subject: [PATCH 1309/1328] 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 | 61 ++++++++++++++++++++++++++++ + 4 files changed, 86 insertions(+), 1 deletion(-) + +diff --git a/xen/arch/x86/boot/trampoline.S b/xen/arch/x86/boot/trampoline.S +index 6440f31568..41eb3feaf0 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 8505f37210..59cdc3f2e9 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 __BOOT_DEFS_H__ + #define _txt(x) _p(x) +diff --git a/xen/arch/x86/include/asm/processor.h b/xen/arch/x86/include/asm/processor.h +index f8f757a8a8..9e89f72912 100644 +--- a/xen/arch/x86/include/asm/processor.h ++++ b/xen/arch/x86/include/asm/processor.h +@@ -641,6 +641,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 7aa899dac3..8cd2bc4573 100644 +--- a/xen/arch/x86/smpboot.c ++++ b/xen/arch/x86/smpboot.c +@@ -39,6 +39,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -331,6 +332,29 @@ void 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]); +@@ -424,6 +448,33 @@ void start_secondary(void *unused) + startup_cpu_idle_loop(); + } + ++static int wake_aps_in_txt(unsigned long trampoline_rm) ++{ ++ 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); ++ ++#define trampoline_relative(x) \ ++ (trampoline_rm + ((char *)(x) - trampoline_realmode_entry)) ++ ++ uint32_t join[4] = { ++ trampoline_gdt[1], /* GDT limit */ ++ trampoline_relative(trampoline_gdt), /* GDT base */ ++ TXT_AP_BOOT_CS, /* CS selector, DS = CS+8 */ ++ trampoline_relative(txt_ap_entry) /* EIP */ ++ }; ++ ++#undef trampoline_relative ++ ++ 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; +@@ -446,6 +497,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(start_eip); ++ + /* + * Be paranoid about clearing APIC errors. + */ +@@ -1153,6 +1207,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(); +-- +2.46.0 + diff --git a/1310-arch-x86-don-t-access-x86_cpu_to_apicid-directly-use.patch b/1310-arch-x86-don-t-access-x86_cpu_to_apicid-directly-use.patch new file mode 100644 index 0000000..c9a1bf5 --- /dev/null +++ b/1310-arch-x86-don-t-access-x86_cpu_to_apicid-directly-use.patch @@ -0,0 +1,265 @@ +From b9097f06f2ba539af16a58969f689b4ade373555 Mon Sep 17 00:00:00 2001 +From: Krystian Hebel +Date: Thu, 1 Jun 2023 16:05:18 +0200 +Subject: [PATCH 1310/1328] 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 44347e3390..2ae666ec94 100644 +--- a/xen/arch/x86/acpi/cpu_idle.c ++++ b/xen/arch/x86/acpi/cpu_idle.c +@@ -1260,7 +1260,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; + } + +@@ -1320,7 +1320,7 @@ static void print_cx_pminfo(uint32_t cpu, struct xen_processor_power *power) + + static void repark_cpu(int 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 43831b92d1..55d0ef919c 100644 +--- a/xen/arch/x86/acpi/lib.c ++++ b/xen/arch/x86/acpi/lib.c +@@ -89,7 +89,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 e43b779036..0feffbf305 100644 +--- a/xen/arch/x86/apic.c ++++ b/xen/arch/x86/apic.c +@@ -985,7 +985,7 @@ __next: + */ + 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 e3d3b8ba73..3b35fef774 100644 +--- a/xen/arch/x86/cpu/mwait-idle.c ++++ b/xen/arch/x86/cpu/mwait-idle.c +@@ -1221,8 +1221,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 5dbd1d8a12..6738449761 100644 +--- a/xen/arch/x86/domain.c ++++ b/xen/arch/x86/domain.c +@@ -1538,7 +1538,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 d8ccab2449..b8cabebe7b 100644 +--- a/xen/arch/x86/mpparse.c ++++ b/xen/arch/x86/mpparse.c +@@ -187,7 +187,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); + } + +@@ -822,12 +822,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 322157fab7..22ff0923d4 100644 +--- a/xen/arch/x86/numa.c ++++ b/xen/arch/x86/numa.c +@@ -340,7 +340,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 27a799161a..890595340e 100644 +--- a/xen/arch/x86/platform_hypercall.c ++++ b/xen/arch/x86/platform_hypercall.c +@@ -588,7 +588,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 49694e10a2..1a4bab89a4 100644 +--- a/xen/arch/x86/setup.c ++++ b/xen/arch/x86/setup.c +@@ -317,7 +317,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 ) +@@ -344,7 +344,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; + + /* +@@ -355,12 +355,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; +@@ -376,9 +376,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 8cd2bc4573..cf45ba21c6 100644 +--- a/xen/arch/x86/smpboot.c ++++ b/xen/arch/x86/smpboot.c +@@ -347,7 +347,7 @@ void 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"); +@@ -1223,7 +1223,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)); + +@@ -1443,7 +1443,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 7697f9ad3f..d3fc2ed637 100644 +--- a/xen/arch/x86/spec_ctrl.c ++++ b/xen/arch/x86/spec_ctrl.c +@@ -717,7 +717,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 42dc360ad6..de9b75c1ec 100644 +--- a/xen/arch/x86/sysctl.c ++++ b/xen/arch/x86/sysctl.c +@@ -59,7 +59,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) ) +-- +2.46.0 + diff --git a/1311-arch-x86-smp-drop-x86_cpu_to_apicid-use-cpu_data-cpu.patch b/1311-arch-x86-smp-drop-x86_cpu_to_apicid-use-cpu_data-cpu.patch new file mode 100644 index 0000000..4251b28 --- /dev/null +++ b/1311-arch-x86-smp-drop-x86_cpu_to_apicid-use-cpu_data-cpu.patch @@ -0,0 +1,156 @@ +From e6a90f0d3de0c5ec68a021fddfc9bfd91174dace Mon Sep 17 00:00:00 2001 +From: Krystian Hebel +Date: Thu, 1 Jun 2023 17:01:59 +0200 +Subject: [PATCH 1311/1328] 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 ad2f5058f0..ce280c914a 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 abc6822b08..b6f9ec10b0 100644 +--- a/xen/arch/x86/include/asm/asm_defns.h ++++ b/xen/arch/x86/include/asm/asm_defns.h +@@ -166,7 +166,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 9e89f72912..339d6e146e 100644 +--- a/xen/arch/x86/include/asm/processor.h ++++ b/xen/arch/x86/include/asm/processor.h +@@ -149,6 +149,8 @@ extern struct cpuinfo_x86 boot_cpu_data; + 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 41a3b6a0da..b0cefdf814 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] +- + #define cpu_is_offline(cpu) unlikely(!cpu_online(cpu)) + extern void cpu_exit_clear(unsigned int cpu); + extern void cpu_uninit(unsigned int cpu); +diff --git a/xen/arch/x86/numa.c b/xen/arch/x86/numa.c +index 22ff0923d4..393e4108c7 100644 +--- a/xen/arch/x86/numa.c ++++ b/xen/arch/x86/numa.c +@@ -324,14 +324,13 @@ custom_param("numa", numa_setup); + /* + * 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 cf45ba21c6..df94e57269 100644 +--- a/xen/arch/x86/smpboot.c ++++ b/xen/arch/x86/smpboot.c +@@ -73,10 +73,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 { +@@ -93,7 +91,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 fba82d6436..cc5eb5a518 100644 +--- a/xen/arch/x86/x86_64/asm-offsets.c ++++ b/xen/arch/x86/x86_64/asm-offsets.c +@@ -186,7 +186,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); +-- +2.46.0 + diff --git a/1312-arch-x86-smp-move-stack_base-to-cpu_data.patch b/1312-arch-x86-smp-move-stack_base-to-cpu_data.patch new file mode 100644 index 0000000..6e96888 --- /dev/null +++ b/1312-arch-x86-smp-move-stack_base-to-cpu_data.patch @@ -0,0 +1,222 @@ +From 9129e7d09307c71a700c63f4e62ee6eb0db01468 Mon Sep 17 00:00:00 2001 +From: Krystian Hebel +Date: Thu, 1 Jun 2023 19:27:22 +0200 +Subject: [PATCH 1312/1328] arch/x86/smp: move stack_base to cpu_data + +Signed-off-by: Krystian Hebel +--- + xen/arch/x86/boot/x86_64.S | 5 ++--- + xen/arch/x86/include/asm/processor.h | 1 + + xen/arch/x86/include/asm/smp.h | 2 +- + xen/arch/x86/setup.c | 6 +++--- + xen/arch/x86/smpboot.c | 25 +++++++++++++------------ + xen/arch/x86/tboot.c | 4 ++-- + xen/arch/x86/traps.c | 4 ++-- + xen/arch/x86/x86_64/asm-offsets.c | 1 + + xen/include/xen/smp.h | 2 -- + 9 files changed, 25 insertions(+), 25 deletions(-) + +diff --git a/xen/arch/x86/boot/x86_64.S b/xen/arch/x86/boot/x86_64.S +index ce280c914a..61040315f9 100644 +--- a/xen/arch/x86/boot/x86_64.S ++++ b/xen/arch/x86/boot/x86_64.S +@@ -33,9 +33,8 @@ ENTRY(__high_start) + cmp %esp, CPUINFO_X86_apicid(%rcx) + jne 1b + +- /* %eax is now Xen CPU index. */ +- lea stack_base(%rip), %rcx +- mov (%rcx, %rax, 8), %rsp ++ /* %rcx is now cpu_data[cpu], read stack base from it. */ ++ mov CPUINFO_X86_stack_base(%rcx), %rsp + + test %rsp,%rsp + jnz 1f +diff --git a/xen/arch/x86/include/asm/processor.h b/xen/arch/x86/include/asm/processor.h +index 339d6e146e..1f78785689 100644 +--- a/xen/arch/x86/include/asm/processor.h ++++ b/xen/arch/x86/include/asm/processor.h +@@ -137,6 +137,7 @@ struct cpuinfo_x86 { + __u32 phys_proc_id; /* package ID of each logical CPU */ + __u32 cpu_core_id; /* core ID of each logical CPU*/ + __u32 compute_unit_id; /* AMD compute unit ID of each logical CPU */ ++ void *stack_base; + unsigned short x86_clflush_size; + } __cacheline_aligned; + +diff --git a/xen/arch/x86/include/asm/smp.h b/xen/arch/x86/include/asm/smp.h +index b0cefdf814..4432a8ea1b 100644 +--- a/xen/arch/x86/include/asm/smp.h ++++ b/xen/arch/x86/include/asm/smp.h +@@ -76,7 +76,7 @@ extern cpumask_t **socket_cpumask; + * by certain scheduling code only. + */ + #define get_cpu_current(cpu) \ +- (get_cpu_info_from_stack((unsigned long)stack_base[cpu])->current_vcpu) ++ (get_cpu_info_from_stack((unsigned long)cpu_data[cpu].stack_base)->current_vcpu) + + extern unsigned int disabled_cpus; + extern bool unaccounted_cpus; +diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c +index 1a4bab89a4..f014b681d9 100644 +--- a/xen/arch/x86/setup.c ++++ b/xen/arch/x86/setup.c +@@ -683,7 +683,7 @@ static void __init noreturn reinit_bsp_stack(void) + /* Update SYSCALL trampolines */ + percpu_traps_init(); + +- stack_base[0] = stack; ++ cpu_data[0].stack_base = stack; + + rc = setup_cpu_root_pgt(0); + if ( rc ) +@@ -1915,8 +1915,8 @@ void __init noreturn __start_xen(unsigned long mbi_p) + /* 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); ++ if ( cpu_data[i].stack_base == NULL ) ++ cpu_data[i].stack_base = cpu_alloc_stack(i); + } + + for_each_present_cpu ( i ) +diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c +index df94e57269..2a36812d6d 100644 +--- a/xen/arch/x86/smpboot.c ++++ b/xen/arch/x86/smpboot.c +@@ -87,13 +87,15 @@ static enum cpu_state { + } cpu_state; + #define set_cpu_state(state) do { smp_mb(); cpu_state = (state); } while (0) + +-void *stack_base[NR_CPUS]; +- + void initialize_cpu_data(unsigned int cpu) + { + uint32_t apicid = cpu_physical_id(cpu); ++ void *stack = cpu_data[cpu].stack_base; ++ + cpu_data[cpu] = boot_cpu_data; ++ + cpu_physical_id(cpu) = apicid; ++ cpu_data[cpu].stack_base = stack; + } + + static bool smp_store_cpu_info(unsigned int id) +@@ -641,8 +643,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); +@@ -918,7 +918,7 @@ int setup_cpu_root_pgt(unsigned int cpu) + + /* Install direct map page table entries for stack, IDT, and TSS. */ + for ( off = rc = 0; !rc && off < STACK_SIZE; off += PAGE_SIZE ) +- rc = clone_mapping(__va(__pa(stack_base[cpu])) + off, rpt); ++ rc = clone_mapping(__va(__pa(cpu_data[cpu].stack_base)) + off, rpt); + + if ( !rc ) + rc = clone_mapping(idt_tables[cpu], rpt); +@@ -1069,10 +1069,10 @@ static void cpu_smpboot_free(unsigned int cpu, bool remove) + FREE_XENHEAP_PAGE(per_cpu(gdt, cpu)); + FREE_XENHEAP_PAGE(idt_tables[cpu]); + +- if ( stack_base[cpu] ) ++ if ( cpu_data[cpu].stack_base ) + { +- memguard_unguard_stack(stack_base[cpu]); +- FREE_XENHEAP_PAGES(stack_base[cpu], STACK_ORDER); ++ memguard_unguard_stack(cpu_data[cpu].stack_base); ++ FREE_XENHEAP_PAGES(cpu_data[cpu].stack_base, STACK_ORDER); + } + } + } +@@ -1106,11 +1106,11 @@ static int cpu_smpboot_alloc(unsigned int cpu) + if ( node != NUMA_NO_NODE ) + memflags = MEMF_node(node); + +- if ( stack_base[cpu] == NULL && +- (stack_base[cpu] = cpu_alloc_stack(cpu)) == NULL ) ++ if ( cpu_data[cpu].stack_base == NULL && ++ (cpu_data[cpu].stack_base = cpu_alloc_stack(cpu)) == NULL ) + goto out; + +- info = get_cpu_info_from_stack((unsigned long)stack_base[cpu]); ++ info = get_cpu_info_from_stack((unsigned long)cpu_data[cpu].stack_base); + info->processor_id = cpu; + info->per_cpu_offset = __per_cpu_offset[cpu]; + +@@ -1225,7 +1225,8 @@ void __init smp_prepare_cpus(void) + boot_cpu_physical_apicid = get_apic_id(); + cpu_physical_id(0) = boot_cpu_physical_apicid; + +- stack_base[0] = (void *)((unsigned long)stack_start & ~(STACK_SIZE - 1)); ++ cpu_data[0].stack_base = (void *) ++ ((unsigned long)stack_start & ~(STACK_SIZE - 1)); + + set_nr_sockets(); + +diff --git a/xen/arch/x86/tboot.c b/xen/arch/x86/tboot.c +index ffd1126dfc..a06719061d 100644 +--- a/xen/arch/x86/tboot.c ++++ b/xen/arch/x86/tboot.c +@@ -238,9 +238,9 @@ static int mfn_in_guarded_stack(unsigned long mfn) + + for ( i = 0; i < nr_cpu_ids; i++ ) + { +- if ( !stack_base[i] ) ++ if ( !cpu_data[i].stack_base ) + continue; +- p = (void *)((unsigned long)stack_base[i] + STACK_SIZE - ++ p = (void *)((unsigned long)cpu_data[i].stack_base + STACK_SIZE - + PRIMARY_STACK_SIZE - PAGE_SIZE); + if ( mfn == virt_to_mfn(p) ) + return -1; +diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c +index 7599bee361..77e69bf80d 100644 +--- a/xen/arch/x86/traps.c ++++ b/xen/arch/x86/traps.c +@@ -623,9 +623,9 @@ void show_stack_overflow(unsigned int cpu, const struct cpu_user_regs *regs) + unsigned long curr_stack_base = esp & ~(STACK_SIZE - 1); + unsigned long esp_top, esp_bottom; + +- if ( _p(curr_stack_base) != stack_base[cpu] ) ++ if ( _p(curr_stack_base) != cpu_data[cpu].stack_base ) + printk("Current stack base %p differs from expected %p\n", +- _p(curr_stack_base), stack_base[cpu]); ++ _p(curr_stack_base), cpu_data[cpu].stack_base); + + esp_bottom = (esp | (STACK_SIZE - 1)) + 1; + esp_top = esp_bottom - PRIMARY_STACK_SIZE; +diff --git a/xen/arch/x86/x86_64/asm-offsets.c b/xen/arch/x86/x86_64/asm-offsets.c +index cc5eb5a518..a8d74fbd20 100644 +--- a/xen/arch/x86/x86_64/asm-offsets.c ++++ b/xen/arch/x86/x86_64/asm-offsets.c +@@ -188,6 +188,7 @@ void __dummy__(void) + + OFFSET(CPUINFO_X86_features, struct cpuinfo_x86, x86_capability); + OFFSET(CPUINFO_X86_apicid, struct cpuinfo_x86, apicid); ++ OFFSET(CPUINFO_X86_stack_base, struct cpuinfo_x86, stack_base); + DEFINE(CPUINFO_X86_sizeof, sizeof(struct cpuinfo_x86)); + BLANK(); + +diff --git a/xen/include/xen/smp.h b/xen/include/xen/smp.h +index 0a9219173f..994fdc4742 100644 +--- a/xen/include/xen/smp.h ++++ b/xen/include/xen/smp.h +@@ -67,8 +67,6 @@ void smp_send_call_function_mask(const cpumask_t *mask); + + int alloc_cpu_id(void); + +-extern void *stack_base[NR_CPUS]; +- + void initialize_cpu_data(unsigned int cpu); + int setup_cpu_root_pgt(unsigned int cpu); + +-- +2.46.0 + diff --git a/1313-arch-x86-smp-call-x2apic_ap_setup-earlier.patch b/1313-arch-x86-smp-call-x2apic_ap_setup-earlier.patch new file mode 100644 index 0000000..951dfce --- /dev/null +++ b/1313-arch-x86-smp-call-x2apic_ap_setup-earlier.patch @@ -0,0 +1,48 @@ +From 4b8b09c88b6c0428b0fb5d7cabfa4b62d94332be Mon Sep 17 00:00:00 2001 +From: Krystian Hebel +Date: Tue, 13 Jun 2023 15:44:36 +0200 +Subject: [PATCH 1313/1328] 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 2a36812d6d..cfb0daf10a 100644 +--- a/xen/arch/x86/smpboot.c ++++ b/xen/arch/x86/smpboot.c +@@ -196,7 +196,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. */ +@@ -386,6 +385,14 @@ void 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. */ +-- +2.46.0 + diff --git a/1314-arch-x86-shutdown-protect-against-recurrent-machine_.patch b/1314-arch-x86-shutdown-protect-against-recurrent-machine_.patch new file mode 100644 index 0000000..801e8ba --- /dev/null +++ b/1314-arch-x86-shutdown-protect-against-recurrent-machine_.patch @@ -0,0 +1,54 @@ +From f43fd9db331a4e76eeaddce06555bb430d62c436 Mon Sep 17 00:00:00 2001 +From: Krystian Hebel +Date: Tue, 13 Jun 2023 15:56:12 +0200 +Subject: [PATCH 1314/1328] 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 7619544d14..32c70505ed 100644 +--- a/xen/arch/x86/shutdown.c ++++ b/xen/arch/x86/shutdown.c +@@ -577,9 +577,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(); + } +-- +2.46.0 + diff --git a/1315-arch-x86-smp-drop-booting_cpu-variable.patch b/1315-arch-x86-smp-drop-booting_cpu-variable.patch new file mode 100644 index 0000000..9ee166c --- /dev/null +++ b/1315-arch-x86-smp-drop-booting_cpu-variable.patch @@ -0,0 +1,121 @@ +From 489fab9280499956e54a25e3c2ce242f438fde48 Mon Sep 17 00:00:00 2001 +From: Krystian Hebel +Date: Tue, 13 Jun 2023 18:58:21 +0200 +Subject: [PATCH 1315/1328] 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 | 13 +++++++++---- + xen/arch/x86/smpboot.c | 16 +++++----------- + 2 files changed, 14 insertions(+), 15 deletions(-) + +diff --git a/xen/arch/x86/boot/x86_64.S b/xen/arch/x86/boot/x86_64.S +index 61040315f9..a5f1f681c9 100644 +--- a/xen/arch/x86/boot/x86_64.S ++++ b/xen/arch/x86/boot/x86_64.S +@@ -20,20 +20,24 @@ 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 + +- /* %rcx is now cpu_data[cpu], read stack base from it. */ ++ /* ++ * At this point: ++ * - %rcx is cpu_data[cpu], read stack base from it, ++ * - %rbx (callee-save) is Xen cpu number, pass it to start_secondary(). ++ */ + mov CPUINFO_X86_stack_base(%rcx), %rsp + + test %rsp,%rsp +@@ -101,6 +105,7 @@ ENTRY(__high_start) + .L_ap_cet_done: + #endif /* CONFIG_XEN_SHSTK || CONFIG_XEN_IBT */ + ++ mov %rbx, %rdi + call start_secondary + BUG /* start_secondary() shouldn't return. */ + +diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c +index cfb0daf10a..e9c6837e99 100644 +--- a/xen/arch/x86/smpboot.c ++++ b/xen/arch/x86/smpboot.c +@@ -234,8 +234,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; + +@@ -323,15 +321,14 @@ static void set_cpu_sibling_map(unsigned int cpu) + } + } + +-void start_secondary(void *unused) ++void 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; +@@ -352,7 +349,6 @@ void 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; + } + } + +@@ -381,9 +377,9 @@ void 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 +@@ -637,8 +633,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. */ +-- +2.46.0 + diff --git a/1316-arch-x86-smp-make-cpu_state-per-CPU.patch b/1316-arch-x86-smp-make-cpu_state-per-CPU.patch new file mode 100644 index 0000000..38417e6 --- /dev/null +++ b/1316-arch-x86-smp-make-cpu_state-per-CPU.patch @@ -0,0 +1,219 @@ +From ce4b2d1ce181dc66afe12ac61fa975e9eb34e095 Mon Sep 17 00:00:00 2001 +From: Krystian Hebel +Date: Fri, 16 Jun 2023 12:18:23 +0200 +Subject: [PATCH 1316/1328] 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/include/asm/processor.h | 1 + + xen/arch/x86/smpboot.c | 80 +++++++++++++++++----------- + 2 files changed, 49 insertions(+), 32 deletions(-) + +diff --git a/xen/arch/x86/include/asm/processor.h b/xen/arch/x86/include/asm/processor.h +index 1f78785689..0e9d9a0d88 100644 +--- a/xen/arch/x86/include/asm/processor.h ++++ b/xen/arch/x86/include/asm/processor.h +@@ -138,6 +138,7 @@ struct cpuinfo_x86 { + __u32 cpu_core_id; /* core ID of each logical CPU*/ + __u32 compute_unit_id; /* AMD compute unit ID of each logical CPU */ + void *stack_base; ++ unsigned int cpu_state; + unsigned short x86_clflush_size; + } __cacheline_aligned; + +diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c +index e9c6837e99..f8c3db2107 100644 +--- a/xen/arch/x86/smpboot.c ++++ b/xen/arch/x86/smpboot.c +@@ -77,15 +77,18 @@ struct cpuinfo_x86 cpu_data[NR_CPUS] = + { [0 ... NR_CPUS-1] .apicid = BAD_APICID }; + + static int cpu_error; +-static enum cpu_state { ++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) ++}; ++#define set_cpu_state(cpu, state) do { \ ++ smp_mb(); \ ++ cpu_data[cpu].cpu_state = (state); \ ++} while (0) + + void initialize_cpu_data(unsigned int cpu) + { +@@ -180,16 +183,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 +@@ -225,12 +219,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_data[cpu].cpu_state != CPU_STATE_ONLINE ) + cpu_relax(); + } + +@@ -325,6 +319,9 @@ void 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. +@@ -354,6 +351,10 @@ void 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_data[cpu].cpu_state != CPU_STATE_CALLOUT ) ++ cpu_relax(); ++ + set_current(idle_vcpu[cpu]); + this_cpu(curr_vcpu) = idle_vcpu[cpu]; + rdmsrl(MSR_EFER, this_cpu(efer)); +@@ -646,26 +647,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_data[cpu].cpu_state == CPU_STATE_INIT ) + break; + udelay(100); + } + +- if ( cpu_state == CPU_STATE_CALLIN ) ++ if ( cpu_data[cpu].cpu_state == 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_data[cpu].cpu_state != CPU_STATE_CALLOUT ) ++ break; ++ udelay(10); ++ } ++ } ++ ++ if ( cpu_data[cpu].cpu_state == CPU_STATE_CALLIN ) + { + /* number CPUs logically, starting from 1 (BSP is 0) */ + Dprintk("OK.\n"); +@@ -673,7 +683,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_data[cpu].cpu_state == CPU_STATE_DEAD ) + { + smp_rmb(); + rc = cpu_error; +@@ -744,7 +754,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) +@@ -1229,6 +1239,12 @@ void __init smp_prepare_cpus(void) + cpu_data[0].stack_base = (void *) + ((unsigned long)stack_start & ~(STACK_SIZE - 1)); + ++ /* Set state as CALLOUT so APs won't change it in initialize_cpu_data() */ ++ boot_cpu_data.cpu_state = CPU_STATE_CALLOUT; ++ ++ /* 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); +@@ -1335,7 +1351,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(); +@@ -1360,7 +1376,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_data[cpu].cpu_state) != CPU_STATE_DEAD ) + { + BUG_ON(seen_state != CPU_STATE_DYING); + mdelay(100); +@@ -1461,7 +1477,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(); +-- +2.46.0 + diff --git a/1317-arch-x86-smp-remove-MONITOR-MWAIT-loop-for-TXT-AP-br.patch b/1317-arch-x86-smp-remove-MONITOR-MWAIT-loop-for-TXT-AP-br.patch new file mode 100644 index 0000000..27d3585 --- /dev/null +++ b/1317-arch-x86-smp-remove-MONITOR-MWAIT-loop-for-TXT-AP-br.patch @@ -0,0 +1,80 @@ +From 69e5ee9fbefe3a1ca17237ab7bd889942db28470 Mon Sep 17 00:00:00 2001 +From: Krystian Hebel +Date: Fri, 16 Jun 2023 14:31:27 +0200 +Subject: [PATCH 1317/1328] 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 f8c3db2107..4eb5506ff9 100644 +--- a/xen/arch/x86/smpboot.c ++++ b/xen/arch/x86/smpboot.c +@@ -327,28 +327,6 @@ void 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. */ +@@ -459,16 +437,19 @@ static int wake_aps_in_txt(unsigned long trampoline_rm) + 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; + + #define trampoline_relative(x) \ + (trampoline_rm + ((char *)(x) - trampoline_realmode_entry)) + +- uint32_t join[4] = { +- trampoline_gdt[1], /* GDT limit */ +- trampoline_relative(trampoline_gdt), /* GDT base */ +- TXT_AP_BOOT_CS, /* CS selector, DS = CS+8 */ +- trampoline_relative(txt_ap_entry) /* EIP */ +- }; ++ join[0] = trampoline_gdt[1]; /* GDT limit */ ++ join[1] = trampoline_relative(trampoline_gdt); /* GDT base */ ++ join[2] = TXT_AP_BOOT_CS; /* CS selector, DS = CS+8 */ ++ join[3] = trampoline_relative(txt_ap_entry); /* EIP */ + + #undef trampoline_relative + +-- +2.46.0 + diff --git a/1318-arch-x86-smp-don-t-send-INIT-SIPI-SIPI-if-AP-is-alre.patch b/1318-arch-x86-smp-don-t-send-INIT-SIPI-SIPI-if-AP-is-alre.patch new file mode 100644 index 0000000..ecb6c1d --- /dev/null +++ b/1318-arch-x86-smp-don-t-send-INIT-SIPI-SIPI-if-AP-is-alre.patch @@ -0,0 +1,82 @@ +From 1f048091eec0bdd868c7427d124f3ceede305296 Mon Sep 17 00:00:00 2001 +From: Krystian Hebel +Date: Fri, 16 Jun 2023 14:41:17 +0200 +Subject: [PATCH 1318/1328] 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 4eb5506ff9..ce37266b13 100644 +--- a/xen/arch/x86/smpboot.c ++++ b/xen/arch/x86/smpboot.c +@@ -607,7 +607,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 +@@ -615,21 +614,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_data[cpu].cpu_state != 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 ) + { +@@ -688,10 +697,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; + } + +-- +2.46.0 + diff --git a/1319-arch-x86-smp-start-APs-in-parallel-during-boot.patch b/1319-arch-x86-smp-start-APs-in-parallel-during-boot.patch new file mode 100644 index 0000000..86b6324 --- /dev/null +++ b/1319-arch-x86-smp-start-APs-in-parallel-during-boot.patch @@ -0,0 +1,128 @@ +From d308d88523f956a1e34bf3b79c2c2e0bfa3ad3dd Mon Sep 17 00:00:00 2001 +From: Krystian Hebel +Date: Fri, 16 Jun 2023 15:45:32 +0200 +Subject: [PATCH 1319/1328] 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 4432a8ea1b..68c8a349fc 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 *, int vector); + void send_IPI_self(int vector); +diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c +index f014b681d9..22cbdbdc88 100644 +--- a/xen/arch/x86/setup.c ++++ b/xen/arch/x86/setup.c +@@ -1919,6 +1919,8 @@ void __init noreturn __start_xen(unsigned long mbi_p) + cpu_data[i].stack_base = 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 ce37266b13..c732e5ace7 100644 +--- a/xen/arch/x86/smpboot.c ++++ b/xen/arch/x86/smpboot.c +@@ -464,7 +464,7 @@ static int wake_aps_in_txt(unsigned long trampoline_rm) + + 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; + + /* +@@ -487,6 +487,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(start_eip); + ++ /* ++ * Use destination shorthand for broadcasting IPIs during boot. ++ */ ++ if ( phys_apicid == BAD_APICID ) ++ sh = APIC_DEST_ALLBUT; ++ + /* + * Be paranoid about clearing APIC errors. + */ +@@ -500,7 +506,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 ) +@@ -517,7 +523,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; +@@ -554,7 +560,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 ) + { +@@ -1202,6 +1208,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) + { + /* +-- +2.46.0 + diff --git a/1320-lib-sha256.c-add-file.patch b/1320-lib-sha256.c-add-file.patch new file mode 100644 index 0000000..59cac03 --- /dev/null +++ b/1320-lib-sha256.c-add-file.patch @@ -0,0 +1,305 @@ +From 14730214ed562757e88a3e08d7adb1bbf0ae9861 Mon Sep 17 00:00:00 2001 +From: Sergii Dmytruk +Date: Mon, 26 Jun 2023 00:17:15 +0300 +Subject: [PATCH 1320/1328] 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 +--- + 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 3820e0bfbb..40f7960ef1 100644 +--- a/xen/lib/Makefile ++++ b/xen/lib/Makefile +@@ -29,6 +29,7 @@ lib-y += strsep.o + lib-y += strspn.o + lib-y += strstr.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..e1507c7dd5 +--- /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 { ++ u32 state[SHA256_DIGEST_SIZE / 4]; ++ u64 count; ++ u8 buf[SHA256_BLOCK_SIZE]; ++}; ++ ++typedef void sha256_block_fn(struct sha256_state *sst, u8 const *src, ++ int blocks); ++ ++static const u32 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 u32 Ch(u32 x, u32 y, u32 z) ++{ ++ return z ^ (x & (y ^ z)); ++} ++ ++static u32 Maj(u32 x, u32 y, u32 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, u32 *W, const u8 *input) ++{ ++ W[I] = get_unaligned_be32((__u32 *)input + I); ++} ++ ++static void BLEND_OP(int I, u32 *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 { \ ++ u32 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 u8 *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, u8 *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(u32 *state, const u8 *input, u32 *W) ++{ ++ u32 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 u8 *input, int blocks) ++{ ++ u32 W[64]; ++ ++ do { ++ sha256_transform(sctx->state, input, W); ++ input += SHA256_BLOCK_SIZE; ++ } while ( --blocks ); ++ ++ memset(W, 0, sizeof(W)); ++} ++ ++void sha256_hash(const u8 *data, unsigned int len, u8 *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); ++} +-- +2.46.0 + diff --git a/1321-x86-tpm.c-support-extending-PCRs-of-TPM2.0.patch b/1321-x86-tpm.c-support-extending-PCRs-of-TPM2.0.patch new file mode 100644 index 0000000..5ce618b --- /dev/null +++ b/1321-x86-tpm.c-support-extending-PCRs-of-TPM2.0.patch @@ -0,0 +1,523 @@ +From 916d06aeb4b76006526f4bdc727480aaadde40e0 Mon Sep 17 00:00:00 2001 +From: Sergii Dmytruk +Date: Wed, 28 Jun 2023 20:23:24 +0300 +Subject: [PATCH 1321/1328] 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 1bd271dbe2..e3e4bda841 100644 +--- a/xen/arch/x86/tpm.c ++++ b/xen/arch/x86/tpm.c +@@ -40,6 +40,15 @@ asm ( + * 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; +@@ -62,6 +71,7 @@ void *memcpy(void *dest, const void *src, size_t n) + #endif /* __EARLY_TPM__ */ + + #include ++#include + + #define TPM_LOC_REG(loc, reg) (0x1000 * (loc) + (reg)) + +@@ -80,6 +90,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) +@@ -160,14 +171,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 { +@@ -182,6 +194,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; +@@ -247,11 +270,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 { +@@ -406,6 +424,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) + { +@@ -431,6 +825,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 + } + } +-- +2.46.0 + diff --git a/1322-x86-tpm.c-implement-event-log-for-TPM2.0.patch b/1322-x86-tpm.c-implement-event-log-for-TPM2.0.patch new file mode 100644 index 0000000..7125da5 --- /dev/null +++ b/1322-x86-tpm.c-implement-event-log-for-TPM2.0.patch @@ -0,0 +1,257 @@ +From 9ab27bc21b1747b95120805a61676b236333fc65 Mon Sep 17 00:00:00 2001 +From: Sergii Dmytruk +Date: Sat, 1 Jul 2023 00:41:35 +0300 +Subject: [PATCH 1322/1328] 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 59cdc3f2e9..8f9f4d9570 100644 +--- a/xen/arch/x86/include/asm/intel_txt.h ++++ b/xen/arch/x86/include/asm/intel_txt.h +@@ -202,6 +202,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 e3e4bda841..283d735b38 100644 +--- a/xen/arch/x86/tpm.c ++++ b/xen/arch/x86/tpm.c +@@ -550,6 +550,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 { +@@ -770,15 +808,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", +@@ -798,6 +833,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, +@@ -828,25 +956,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 ) { +-- +2.46.0 + diff --git a/1323-arch-x86-process-DRTM-policy.patch b/1323-arch-x86-process-DRTM-policy.patch new file mode 100644 index 0000000..30aa7d7 --- /dev/null +++ b/1323-arch-x86-process-DRTM-policy.patch @@ -0,0 +1,282 @@ +From 34f1eaca4d3e7f005b62aed22b568a610ef02ba1 Mon Sep 17 00:00:00 2001 +From: Sergii Dmytruk +Date: Sun, 29 Oct 2023 00:42:04 +0300 +Subject: [PATCH 1323/1328] 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 +--- + xen/arch/x86/include/asm/tpm.h | 11 ++ + xen/arch/x86/setup.c | 10 ++ + xen/arch/x86/tpm.c | 193 +++++++++++++++++++++++++++++++++ + 3 files changed, 214 insertions(+) + +diff --git a/xen/arch/x86/include/asm/tpm.h b/xen/arch/x86/include/asm/tpm.h +index 9bbdf63680..3ca5d3528d 100644 +--- a/xen/arch/x86/include/asm/tpm.h ++++ b/xen/arch/x86/include/asm/tpm.h +@@ -2,6 +2,7 @@ + #define _ASM_X86_TPM_H_ + + #include ++#include + + #define TPM_TIS_BASE 0xFED40000 + #define TPM_TIS_SIZE 0x00010000 +@@ -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 MultibootInfo (MBI) (the MBI address ++ * is assumed to be virtual). */ ++void tpm_process_drtm_policy(const multiboot_info_t *mbi); ++ + #endif /* _ASM_X86_TPM_H_ */ +diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c +index 22cbdbdc88..519e3311f5 100644 +--- a/xen/arch/x86/setup.c ++++ b/xen/arch/x86/setup.c +@@ -56,6 +56,7 @@ + #include + #include + #include ++#include + + /* opt_nosmp: If true, secondary processors are ignored. */ + static bool __initdata opt_nosmp; +@@ -1172,6 +1173,9 @@ void __init noreturn __start_xen(unsigned long mbi_p) + { + /* 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(); + } +@@ -1194,6 +1198,12 @@ void __init noreturn __start_xen(unsigned long mbi_p) + /* 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 ++ * fields of Multiboot modules change their format below. */ ++ if ( slaunch_active ) ++ tpm_process_drtm_policy(mbi); ++ + /* Early kexec reservation (explicit static start address). */ + nr_pages = 0; + for ( i = 0; i < e820.nr_map; i++ ) +diff --git a/xen/arch/x86/tpm.c b/xen/arch/x86/tpm.c +index 283d735b38..58cddf7c8c 100644 +--- a/xen/arch/x86/tpm.c ++++ b/xen/arch/x86/tpm.c +@@ -980,4 +980,197 @@ void __stdcall tpm_extend_mbi(uint32_t *mbi) + tpm_hash_extend(DRTM_LOC, DRTM_DATA_PCR, (uint8_t *)mbi, *mbi, + TXT_EVTYPE_SLAUNCH, NULL, 0); + } ++#else ++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), TXT_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 multiboot_info_t *mbi) ++{ ++ uint32_t i; ++ module_t *mods; ++ 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); ++ ++ mods = __va(mbi->mods_addr); ++ for ( i = 0; i < mbi->mods_count; i++ ) { ++ uint16_t j; ++ uint64_t start = mods[i].mod_start; ++ uint64_t size = mods[i].mod_end - mods[i].mod_start; ++ ++ for ( j = 0; j < policy->nr_entries; j++ ) { ++ if ( policy_entry[j].entity_type != SLR_ET_MULTIBOOT2_MODULE ) ++ continue; ++ ++ if ( policy_entry[j].entity == start && ++ policy_entry[j].size == 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(mods[i].string), 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 ( mbi->mods_count != num_mod_entries ) { ++ panic("Unexpected number of Multiboot modules: %d instead of %d\n", ++ (int)mbi->mods_count, (int)num_mod_entries); ++ } ++} ++ ++void tpm_process_drtm_policy(const multiboot_info_t *mbi) ++{ ++ 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, mbi); ++ /* 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, ++ TXT_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; ++ } ++} + #endif +-- +2.46.0 + diff --git a/1324-arch-x86-extract-slaunch-unit.patch b/1324-arch-x86-extract-slaunch-unit.patch new file mode 100644 index 0000000..54498d1 --- /dev/null +++ b/1324-arch-x86-extract-slaunch-unit.patch @@ -0,0 +1,731 @@ +From 7665e099a92dfa3665da8098ac41681928124ae5 Mon Sep 17 00:00:00 2001 +From: Sergii Dmytruk +Date: Sat, 16 Mar 2024 21:25:16 +0200 +Subject: [PATCH 1324/1328] arch/x86: extract slaunch unit + +To collect its core functionality in one place instead of having some in +intel_txt and other in tpm units. + +TXT_EVTYPE_* now live in and are called +DLE_EVTYPE_* despite being based on TXT specification. This way code +for non-Intel won't need to include TXT header. + +No functional changes. + +Signed-off-by: Sergii Dmytruk +--- + 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/intel_txt.c | 27 +-- + xen/arch/x86/setup.c | 1 + + xen/arch/x86/slaunch.c | 239 +++++++++++++++++++++++++++ + xen/arch/x86/smpboot.c | 1 + + xen/arch/x86/tpm.c | 197 +--------------------- + 9 files changed, 301 insertions(+), 270 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 d967aabf29..884929e051 100644 +--- a/xen/arch/x86/Makefile ++++ b/xen/arch/x86/Makefile +@@ -60,6 +60,7 @@ obj-y += 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 f836fec189..5b2d960a88 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 8f9f4d9570..112f670816 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[]; + +@@ -94,8 +92,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. +@@ -333,39 +329,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) + { +@@ -378,17 +341,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/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 519e3311f5..75e5dbb725 100644 +--- a/xen/arch/x86/setup.c ++++ b/xen/arch/x86/setup.c +@@ -56,6 +56,7 @@ + #include + #include + #include ++#include + #include + + /* opt_nosmp: If true, secondary processors are ignored. */ +diff --git a/xen/arch/x86/slaunch.c b/xen/arch/x86/slaunch.c +new file mode 100644 +index 0000000000..07500ee8db +--- /dev/null ++++ b/xen/arch/x86/slaunch.c +@@ -0,0 +1,239 @@ ++#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 multiboot_info_t *mbi) ++{ ++ uint32_t i; ++ module_t *mods; ++ 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); ++ ++ mods = __va(mbi->mods_addr); ++ for ( i = 0; i < mbi->mods_count; i++ ) ++ { ++ uint16_t j; ++ uint64_t start = mods[i].mod_start; ++ uint64_t size = mods[i].mod_end - mods[i].mod_start; ++ ++ for ( j = 0; j < policy->nr_entries; j++ ) ++ { ++ if ( policy_entry[j].entity_type != SLR_ET_MULTIBOOT2_MODULE ) ++ continue; ++ ++ if ( policy_entry[j].entity == start && ++ policy_entry[j].size == 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(mods[i].string), 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 ( mbi->mods_count != num_mod_entries ) ++ { ++ panic("Unexpected number of Multiboot modules: %d instead of %d\n", ++ (int)mbi->mods_count, (int)num_mod_entries); ++ } ++} ++ ++void tpm_process_drtm_policy(const multiboot_info_t *mbi) ++{ ++ 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, mbi); ++ /* 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 c732e5ace7..ecbc645ae1 100644 +--- a/xen/arch/x86/smpboot.c ++++ b/xen/arch/x86/smpboot.c +@@ -40,6 +40,7 @@ + #include + #include + #include ++#include + #include + #include + #include +diff --git a/xen/arch/x86/tpm.c b/xen/arch/x86/tpm.c +index 58cddf7c8c..b075dafaf2 100644 +--- a/xen/arch/x86/tpm.c ++++ b/xen/arch/x86/tpm.c +@@ -29,6 +29,7 @@ asm ( + + #include "boot/defs.h" + #include "include/asm/intel_txt.h" ++#include "include/asm/slaunch.h" + #include "include/asm/tpm.h" + #ifdef __va + #error "__va defined in non-paged mode!" +@@ -66,6 +67,7 @@ void *memcpy(void *dest, const void *src, size_t n) + #include + #include + #include ++#include + #include + + #endif /* __EARLY_TPM__ */ +@@ -978,199 +980,6 @@ void __stdcall 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); +-} +-#else +-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), TXT_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 multiboot_info_t *mbi) +-{ +- uint32_t i; +- module_t *mods; +- 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); +- +- mods = __va(mbi->mods_addr); +- for ( i = 0; i < mbi->mods_count; i++ ) { +- uint16_t j; +- uint64_t start = mods[i].mod_start; +- uint64_t size = mods[i].mod_end - mods[i].mod_start; +- +- for ( j = 0; j < policy->nr_entries; j++ ) { +- if ( policy_entry[j].entity_type != SLR_ET_MULTIBOOT2_MODULE ) +- continue; +- +- if ( policy_entry[j].entity == start && +- policy_entry[j].size == 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(mods[i].string), 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 ( mbi->mods_count != num_mod_entries ) { +- panic("Unexpected number of Multiboot modules: %d instead of %d\n", +- (int)mbi->mods_count, (int)num_mod_entries); +- } +-} +- +-void tpm_process_drtm_policy(const multiboot_info_t *mbi) +-{ +- 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, mbi); +- /* 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, +- TXT_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; +- } ++ DLE_EVTYPE_SLAUNCH, NULL, 0); + } + #endif +-- +2.46.0 + diff --git a/1325-x86-boot-introduce-slaunch_slrt-global-variable.patch b/1325-x86-boot-introduce-slaunch_slrt-global-variable.patch new file mode 100644 index 0000000..cb505af --- /dev/null +++ b/1325-x86-boot-introduce-slaunch_slrt-global-variable.patch @@ -0,0 +1,283 @@ +From 0480b882d6b56c020a57d6f05d6ae30924775274 Mon Sep 17 00:00:00 2001 +From: Sergii Dmytruk +Date: Thu, 21 Mar 2024 19:35:10 +0200 +Subject: [PATCH 1325/1328] 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 +--- + xen/arch/x86/boot/Makefile | 2 +- + xen/arch/x86/boot/head.S | 32 +++++++++++++------ + .../x86/boot/{txt_early.c => slaunch_early.c} | 19 ++++++++--- + 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, 52 insertions(+), 35 deletions(-) + rename xen/arch/x86/boot/{txt_early.c => slaunch_early.c} (91%) + +diff --git a/xen/arch/x86/boot/Makefile b/xen/arch/x86/boot/Makefile +index 913fa9d2c6..e1cb421ad3 100644 +--- a/xen/arch/x86/boot/Makefile ++++ b/xen/arch/x86/boot/Makefile +@@ -1,6 +1,6 @@ + obj-bin-y += head.o + +-head-bin-objs := cmdline.o reloc.o txt_early.o tpm_early.o ++head-bin-objs := cmdline.o reloc.o slaunch_early.o tpm_early.o + + nocov-y += $(head-bin-objs) + noubsan-y += $(head-bin-objs) +diff --git a/xen/arch/x86/boot/head.S b/xen/arch/x86/boot/head.S +index 7ea50f0098..4efe47e85a 100644 +--- a/xen/arch/x86/boot/head.S ++++ b/xen/arch/x86/boot/head.S +@@ -527,21 +527,33 @@ __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) + +- /* Push arguments to stack and call txt_early_tests(). */ ++ /* Prepare space for output parameter of slaunch_early_tests(), which is ++ * a structure of two uint32_t fields. */ ++ sub $8, %esp ++ ++ /* Push arguments to stack and call slaunch_early_tests(). */ ++ push %esp /* pointer to output structure */ + push $sym_offs(__2M_rwdata_end) /* end of target image */ + push $sym_offs(_start) /* target base address */ + push %esi /* load base address */ +- call txt_early_tests ++ call slaunch_early_tests + +- /* +- * txt_early_tests() returns MBI address, pass it to tpm_extend_mbi() +- * and store for later in EBX. +- */ +- push %eax +- movl %eax,%ebx ++ /* Move outputs of slaunch_early_tests() from stack into registers. */ ++ pop %ebx /* physical MBI address */ ++ pop %edx /* physical SLRT address */ ++ ++ /* Save physical address of SLRT for C code. */ ++ mov %edx, sym_esi(slaunch_slrt) ++ ++ /* Push arguments to stack and call tpm_extend_mbi(). */ ++ push %edx /* SLRT address because early code has no slaunch_slrt */ ++ push %ebx /* MBI address */ + call tpm_extend_mbi + + /* Move magic number expected by Multiboot 2 to EAX and fall through. */ +@@ -878,8 +890,8 @@ reloc: + .incbin "reloc.bin" + + ALIGN +-txt_early_tests: +- .incbin "txt_early.bin" ++slaunch_early_tests: ++ .incbin "slaunch_early.bin" + + ALIGN + tpm_extend_mbi: +diff --git a/xen/arch/x86/boot/txt_early.c b/xen/arch/x86/boot/slaunch_early.c +similarity index 91% +rename from xen/arch/x86/boot/txt_early.c +rename to xen/arch/x86/boot/slaunch_early.c +index 23ee734c47..3edf40778a 100644 +--- a/xen/arch/x86/boot/txt_early.c ++++ b/xen/arch/x86/boot/slaunch_early.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2022-2023 3mdeb Sp. z o.o. All rights reserved. ++ * 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 +@@ -23,11 +23,18 @@ asm ( + " .text \n" + " .globl _start \n" + "_start: \n" +- " jmp txt_early_tests \n" ++ " jmp slaunch_early_tests \n" + ); + + #include "defs.h" + #include "../include/asm/intel_txt.h" ++#include "../include/asm/slaunch.h" ++ ++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, +@@ -105,9 +112,10 @@ static void verify_pmr_ranges(struct txt_os_mle_data *os_mle, + */ + } + +-uint32_t __stdcall txt_early_tests(uint32_t load_base_addr, ++void __stdcall 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; +@@ -128,5 +136,6 @@ uint32_t __stdcall 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 112f670816..e6c6a06be1 100644 +--- a/xen/arch/x86/include/asm/intel_txt.h ++++ b/xen/arch/x86/include/asm/intel_txt.h +@@ -329,14 +329,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 07500ee8db..cfb53a0eb5 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 b075dafaf2..f05f1bc37b 100644 +--- a/xen/arch/x86/tpm.c ++++ b/xen/arch/x86/tpm.c +@@ -36,6 +36,8 @@ asm ( + #endif + #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 +@@ -936,9 +938,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(evt_log_addr); + + if ( is_tpm12() ) { +@@ -976,8 +976,12 @@ void tpm_hash_extend(unsigned loc, unsigned pcr, uint8_t *buf, unsigned size, + } + + #ifdef __EARLY_TPM__ +-void __stdcall tpm_extend_mbi(uint32_t *mbi) ++void __stdcall 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); +-- +2.46.0 + diff --git a/1326-x86-boot-find-MBI-and-SLRT-on-AMD.patch b/1326-x86-boot-find-MBI-and-SLRT-on-AMD.patch new file mode 100644 index 0000000..bc7ae25 --- /dev/null +++ b/1326-x86-boot-find-MBI-and-SLRT-on-AMD.patch @@ -0,0 +1,124 @@ +From cecbab10cb5e25050d6c684f624f4b7052fb24c5 Mon Sep 17 00:00:00 2001 +From: Sergii Dmytruk +Date: Thu, 21 Mar 2024 19:41:06 +0200 +Subject: [PATCH 1326/1328] 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 +--- + xen/arch/x86/boot/head.S | 2 ++ + xen/arch/x86/boot/slaunch_early.c | 30 ++++++++++++++++++++++++++++++ + xen/arch/x86/include/asm/slaunch.h | 17 +++++++++++++++++ + 3 files changed, 49 insertions(+) + +diff --git a/xen/arch/x86/boot/head.S b/xen/arch/x86/boot/head.S +index 4efe47e85a..093f894850 100644 +--- a/xen/arch/x86/boot/head.S ++++ b/xen/arch/x86/boot/head.S +@@ -539,6 +539,8 @@ __start: + + /* Push arguments to stack and call slaunch_early_tests(). */ + push %esp /* pointer to output structure */ ++ push %ebp /* Slaunch parameter on AMD */ ++ push %ebx /* Multiboot parameter */ + push $sym_offs(__2M_rwdata_end) /* end of target image */ + push $sym_offs(_start) /* target base address */ + push %esi /* load base address */ +diff --git a/xen/arch/x86/boot/slaunch_early.c b/xen/arch/x86/boot/slaunch_early.c +index 3edf40778a..a33db3bd98 100644 +--- a/xen/arch/x86/boot/slaunch_early.c ++++ b/xen/arch/x86/boot/slaunch_early.c +@@ -29,6 +29,7 @@ asm ( + #include "defs.h" + #include "../include/asm/intel_txt.h" + #include "../include/asm/slaunch.h" ++#include "../include/asm/x86-vendors.h" + + struct early_tests_results + { +@@ -36,6 +37,16 @@ struct early_tests_results + uint32_t slrt_pa; + } __packed; + ++static bool is_intel_cpu(void) ++{ ++ /* No boot_cpu_data in early code. */ ++ uint32_t eax, ebx, ecx, edx; ++ cpuid(0x00000000, &eax, &ebx, &ecx, &edx); ++ 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, +@@ -115,6 +126,8 @@ static void verify_pmr_ranges(struct txt_os_mle_data *os_mle, + void __stdcall slaunch_early_tests(uint32_t load_base_addr, + uint32_t tgt_base_addr, + uint32_t tgt_end_addr, ++ uint32_t multiboot_param, ++ uint32_t slaunch_param, + struct early_tests_results *result) + { + void *txt_heap; +@@ -122,6 +135,23 @@ void __stdcall 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. ++ */ ++ ++ const uint16_t *sl_header = (void *)slaunch_param; ++ /* secure-kernel-loader passes MBI as a parameter for Multiboot ++ * kernel. */ ++ result->mbi_pa = multiboot_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]; ++ return; ++ } ++ + /* Clear the TXT error registers for a clean start of day */ + write_txt_reg(TXTCR_ERRORCODE, 0); + +diff --git a/xen/arch/x86/include/asm/slaunch.h b/xen/arch/x86/include/asm/slaunch.h +index 70101bb5d6..70b017b065 100644 +--- a/xen/arch/x86/include/asm/slaunch.h ++++ b/xen/arch/x86/include/asm/slaunch.h +@@ -17,6 +17,23 @@ + #define DLE_EVTYPE_SLAUNCH_START (TXT_EVTYPE_BASE + 0x103) + #define DLE_EVTYPE_SLAUNCH_END (TXT_EVTYPE_BASE + 0x104) + ++#ifndef cpuid ++/* ++ * Generic CPUID function ++ * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx ++ * resulting in stale register contents being returned. ++ * ++ * Copied from processor.h because that header can't be included by early code. ++ */ ++#define cpuid(_op,_eax,_ebx,_ecx,_edx) \ ++ asm volatile ( "cpuid" \ ++ : "=a" (*(int *)(_eax)), \ ++ "=b" (*(int *)(_ebx)), \ ++ "=c" (*(int *)(_ecx)), \ ++ "=d" (*(int *)(_edx)) \ ++ : "0" (_op), "2" (0) ) ++#endif ++ + extern bool slaunch_active; + extern uint32_t slaunch_slrt; /* physical address */ + +-- +2.46.0 + diff --git a/1327-arch-x86-move-generic-memory-mapping-and-protection-.patch b/1327-arch-x86-move-generic-memory-mapping-and-protection-.patch new file mode 100644 index 0000000..ac356f5 --- /dev/null +++ b/1327-arch-x86-move-generic-memory-mapping-and-protection-.patch @@ -0,0 +1,174 @@ +From 16aaa2d86404a09f6ca8bccf885fee963248a501 Mon Sep 17 00:00:00 2001 +From: Sergii Dmytruk +Date: Fri, 22 Mar 2024 00:40:12 +0200 +Subject: [PATCH 1327/1328] 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 70b017b065..ea20a97e94 100644 +--- a/xen/arch/x86/include/asm/slaunch.h ++++ b/xen/arch/x86/include/asm/slaunch.h +@@ -57,6 +57,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 75e5dbb725..e53b973603 100644 +--- a/xen/arch/x86/setup.c ++++ b/xen/arch/x86/setup.c +@@ -55,7 +55,6 @@ + #include + #include + #include +-#include + #include + #include + +@@ -1172,13 +1171,15 @@ void __init noreturn __start_xen(unsigned long mbi_p) + + 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 cfb53a0eb5..0f05a7cb2c 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); ++ ++ 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); ++ ++ /* Vendor-specific part. */ ++ map_txt_mem_regions(); ++} ++ ++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); +-- +2.46.0 + diff --git a/1328-arch-x86-support-slaunch-with-AMD-SKINIT.patch b/1328-arch-x86-support-slaunch-with-AMD-SKINIT.patch new file mode 100644 index 0000000..f46c025 --- /dev/null +++ b/1328-arch-x86-support-slaunch-with-AMD-SKINIT.patch @@ -0,0 +1,289 @@ +From 6c55f68a5187ff603563b1fb361c5bf8209dbf7f Mon Sep 17 00:00:00 2001 +From: Sergii Dmytruk +Date: Sun, 17 Mar 2024 00:58:26 +0200 +Subject: [PATCH 1328/1328] 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 +--- + 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 | 62 ++++++++++++++++++++++++++- + 4 files changed, 118 insertions(+), 16 deletions(-) + +diff --git a/xen/arch/x86/e820.c b/xen/arch/x86/e820.c +index 5b2d960a88..896921b1c5 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 ea20a97e94..2af67a17f7 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 0f05a7cb2c..b18b882f74 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; +@@ -49,7 +66,14 @@ void __init map_slaunch_mem_regions(void) + map_l2((unsigned long)evt_log_addr, evt_log_size); + + /* Vendor-specific part. */ +- 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); ++ } + } + + void __init protect_slaunch_mem_regions(void) +@@ -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 f05f1bc37b..6442c7110f 100644 +--- a/xen/arch/x86/tpm.c ++++ b/xen/arch/x86/tpm.c +@@ -31,6 +31,7 @@ asm ( + #include "include/asm/intel_txt.h" + #include "include/asm/slaunch.h" + #include "include/asm/tpm.h" ++#include "include/asm/x86-vendors.h" + #ifdef __va + #error "__va defined in non-paged mode!" + #endif +@@ -63,15 +64,31 @@ void *memcpy(void *dest, const void *src, size_t n) + return dest; + } + ++static bool is_amd_cpu(void) ++{ ++ /* No boot_cpu_data in early code. */ ++ uint32_t eax, ebx, ecx, edx; ++ cpuid(0x00000000, &eax, &ebx, &ecx, &edx); ++ return ebx == X86_VENDOR_AMD_EBX ++ && ecx == X86_VENDOR_AMD_ECX ++ && edx == X86_VENDOR_AMD_EDX; ++} ++ + #else /* __EARLY_TPM__ */ + + #include + #include + #include + #include ++#include + #include + #include + ++static bool is_amd_cpu(void) ++{ ++ return boot_cpu_data.x86_vendor == X86_VENDOR_AMD; ++} ++ + #endif /* __EARLY_TPM__ */ + + #include +@@ -260,6 +277,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]; +@@ -402,6 +434,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); + + /* +@@ -837,11 +878,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)); + +@@ -874,7 +932,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; + +-- +2.46.0 + diff --git a/xen.spec.in b/xen.spec.in index 6ea368b..c258ec9 100644 --- a/xen.spec.in +++ b/xen.spec.in @@ -201,6 +201,37 @@ Patch1200: 1200-hypercall-XENMEM_get_mfn_from_pfn.patch Patch1201: 1201-patch-gvt-hvmloader.patch.patch Patch1202: 1202-libxl-Add-partially-Intel-GVT-g-support-xengt-device.patch +# Secure Launch support patches +Patch1300: 1300-x86-include-asm-intel_txt.h-constants-and-accessors-.patch +Patch1301: 1301-x86-boot-add-MLE-header-and-new-entry-point.patch +Patch1302: 1302-x86-boot-txt_early-add-early-TXT-tests-and-restore-M.patch +Patch1303: 1303-include-xen-slr_table.h-Secure-Launch-Resource-Table.patch +Patch1304: 1304-xen-arch-x86-reserve-TXT-memory.patch +Patch1305: 1305-x86-intel_txt.c-restore-boot-MTRRs.patch +Patch1306: 1306-lib-sha1.c-add-file.patch +Patch1307: 1307-x86-tpm.c-code-for-early-hashing-and-extending-PCRs-.patch +Patch1308: 1308-x86-boot-choose-AP-stack-based-on-APIC-ID.patch +Patch1309: 1309-x86-smpboot.c-TXT-AP-bringup.patch +Patch1310: 1310-arch-x86-don-t-access-x86_cpu_to_apicid-directly-use.patch +Patch1311: 1311-arch-x86-smp-drop-x86_cpu_to_apicid-use-cpu_data-cpu.patch +Patch1312: 1312-arch-x86-smp-move-stack_base-to-cpu_data.patch +Patch1313: 1313-arch-x86-smp-call-x2apic_ap_setup-earlier.patch +Patch1314: 1314-arch-x86-shutdown-protect-against-recurrent-machine_.patch +Patch1315: 1315-arch-x86-smp-drop-booting_cpu-variable.patch +Patch1316: 1316-arch-x86-smp-make-cpu_state-per-CPU.patch +Patch1317: 1317-arch-x86-smp-remove-MONITOR-MWAIT-loop-for-TXT-AP-br.patch +Patch1318: 1318-arch-x86-smp-don-t-send-INIT-SIPI-SIPI-if-AP-is-alre.patch +Patch1319: 1319-arch-x86-smp-start-APs-in-parallel-during-boot.patch +Patch1320: 1320-lib-sha256.c-add-file.patch +Patch1321: 1321-x86-tpm.c-support-extending-PCRs-of-TPM2.0.patch +Patch1322: 1322-x86-tpm.c-implement-event-log-for-TPM2.0.patch +Patch1323: 1323-arch-x86-process-DRTM-policy.patch +Patch1324: 1324-arch-x86-extract-slaunch-unit.patch +Patch1325: 1325-x86-boot-introduce-slaunch_slrt-global-variable.patch +Patch1326: 1326-x86-boot-find-MBI-and-SLRT-on-AMD.patch +Patch1327: 1327-arch-x86-move-generic-memory-mapping-and-protection-.patch +Patch1328: 1328-arch-x86-support-slaunch-with-AMD-SKINIT.patch + %if %build_qemutrad BuildRequires: libidn-devel zlib-devel SDL-devel curl-devel BuildRequires: libX11-devel gtk2-devel libaio-devel