From nobody Fri Oct 31 16:06:12 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org ARC-Seal: i=1; a=rsa-sha256; t=1748611148; cv=none; d=zohomail.com; s=zohoarc; b=jwklsPWP9TNBqPdsCN8CWf8TLhjKYWWW6znemmIMHZvRwW3FpiICk1uO7wyi0t7yM+9RH/hOOhuhj4IaugP8KqsiqgcxNVzeqkwK81ow/qKPyVeicoypKcOVwmLtBKYI7XG8xzXnRR299EVIwO2Z43NCCygjRTFUD4i9Cso+bU4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1748611148; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=Nf38lpeiCUvbLLteadUfdEVFOEAXLH0XFiAoqTSi818=; b=IslacUxn0MfhzdgwdY4ZEQO1ERqFfaAIHa0l/b6Eg2u+DekmKQy6CdAS0d+WRu+/4cUkNEW45ts7HcqhWyh4RiG8f4YjgniwlU/Shj9OM+WqZOORyEbr56mv+31ceW9hqLxa8tAr8/lxtCObfwQMi9Twx6kw0bcS5zR6SaoyBE0= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1748611148027837.0535383056158; Fri, 30 May 2025 06:19:08 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1000937.1381166 (Exim 4.92) (envelope-from ) id 1uKzdK-0001V4-Np; Fri, 30 May 2025 13:18:50 +0000 Received: by outflank-mailman (output) from mailman id 1000937.1381166; Fri, 30 May 2025 13:18:50 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1uKzdK-0001Us-Jg; Fri, 30 May 2025 13:18:50 +0000 Received: by outflank-mailman (input) for mailman id 1000937; Fri, 30 May 2025 13:18:49 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1uKzdI-0008Jy-UG for xen-devel@lists.xenproject.org; Fri, 30 May 2025 13:18:49 +0000 Received: from 4.mo576.mail-out.ovh.net (4.mo576.mail-out.ovh.net [46.105.42.102]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id 9eb32284-3d58-11f0-a2ff-13f23c93f187; Fri, 30 May 2025 15:18:48 +0200 (CEST) Received: from director1.ghost.mail-out.ovh.net (unknown [10.108.25.252]) by mo576.mail-out.ovh.net (Postfix) with ESMTP id 4b83j33X41z32V2 for ; Fri, 30 May 2025 13:18:47 +0000 (UTC) Received: from ghost-submission-5b5ff79f4f-r8cb6 (unknown [10.110.118.183]) by director1.ghost.mail-out.ovh.net (Postfix) with ESMTPS id BDA71C4523; Fri, 30 May 2025 13:18:46 +0000 (UTC) Received: from 3mdeb.com ([37.59.142.114]) by ghost-submission-5b5ff79f4f-r8cb6 with ESMTPSA id HZerJTawOWi91goAdfCxkA (envelope-from ); Fri, 30 May 2025 13:18:46 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: 9eb32284-3d58-11f0-a2ff-13f23c93f187 Authentication-Results: garm.ovh; auth=pass (GARM-114S008955e152b-4069-4f80-bee0-b9936b0ef95e, A4E380CC922F0B59227EC5DCC46884561651840B) smtp.auth=sergii.dmytruk@3mdeb.com X-OVh-ClientIp: 176.111.184.221 From: Sergii Dmytruk To: xen-devel@lists.xenproject.org Cc: Jan Beulich , Andrew Cooper , =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= , "Daniel P. Smith" , Ross Philipson , trenchboot-devel@googlegroups.com Subject: [PATCH v3 06/22] xen/arch/x86: reserve TXT memory during Slaunch Date: Fri, 30 May 2025 16:17:48 +0300 Message-ID: <8d5ba2e7a0a8bd05bb9cdb89db3f15b831f7f4f7.1748611041.git.sergii.dmytruk@3mdeb.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Ovh-Tracer-Id: 12697617674837472412 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgeeffedrtddtgddvleduvdculddtuddrgeefvddrtddtmdcutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemucehtddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjughrpefhvfevufffkffojghfgggtgfesthekredtredtjeenucfhrhhomhepufgvrhhgihhiucffmhihthhruhhkuceoshgvrhhgihhirdgumhihthhruhhkseefmhguvggsrdgtohhmqeenucggtffrrghtthgvrhhnpeegkeffieeitdevkefhudegffevieeggfelgedvgeehffdtteehfeeuleeiudekvdenucfkphepuddvjedrtddrtddruddpudejiedrudduuddrudekgedrvddvuddpfeejrdehledrudegvddruddugeenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepihhnvghtpeduvdejrddtrddtrddupdhmrghilhhfrhhomhepshgvrhhgihhirdgumhihthhruhhkseefmhguvggsrdgtohhmpdhnsggprhgtphhtthhopedupdhrtghpthhtohepgigvnhdquggvvhgvlheslhhishhtshdrgigvnhhprhhojhgvtghtrdhorhhgpdfovfetjfhoshhtpehmohehjeeimgdpmhhouggvpehsmhhtphhouhht DKIM-Signature: a=rsa-sha256; bh=Nf38lpeiCUvbLLteadUfdEVFOEAXLH0XFiAoqTSi818=; c=relaxed/relaxed; d=3mdeb.com; h=From; s=ovhmo3617313-selector1; t=1748611127; v=1; b=dzUMtDoyKOU0Pn3wBrv6GNv6AvXgVZcONN70y/Fa52eEaV8APHKYIBZfRZ5P5cSR3XvmduBS FkRC7++v+5Q8edt/dfGfWy+TmCGS7wjH1RcLEpwFm1ib3WiLd70b+8cuYs2NitINj4DNfdhsdhM DX8PLEX0saHV9VEYrQFATBYf8j90PIRCq9f3Yo0ETW8HOKYk7XqTPXBduea4oFbT9x9iAEVxqop zQuv4MaDyjxzoFKIBh08xbe3i6gRfALEvPjejUfi3K2UGG8r60AB28d3KrDuAALMcFFrgoWvxa0 EWBbjQTNdb0eGBFaT1VCV0f9tqtTEQMwNzmLYNsKxkB/w== X-ZohoMail-DKIM: pass (identity @3mdeb.com) X-ZM-MESSAGEID: 1748611150274116600 From: Kacper Stojek TXT heap, SINIT and TXT private space are marked as reserved or unused in e820 to protect from unintended uses. Signed-off-by: Kacper Stojek Signed-off-by: Krystian Hebel Signed-off-by: Micha=C5=82 =C5=BBygowski Signed-off-by: Sergii Dmytruk --- xen/arch/x86/Makefile | 1 + xen/arch/x86/include/asm/intel-txt.h | 6 ++ xen/arch/x86/include/asm/mm.h | 3 + xen/arch/x86/include/asm/slaunch.h | 44 +++++++++++ xen/arch/x86/intel-txt.c | 113 +++++++++++++++++++++++++++ xen/arch/x86/setup.c | 10 ++- xen/arch/x86/slaunch.c | 98 ++++++++++++++++++++++- 7 files changed, 271 insertions(+), 4 deletions(-) create mode 100644 xen/arch/x86/intel-txt.c diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile index aa20eb42b5..5788898166 100644 --- a/xen/arch/x86/Makefile +++ b/xen/arch/x86/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_GDBSX) +=3D gdbsx.o obj-y +=3D hypercall.o obj-y +=3D i387.o obj-y +=3D i8259.o +obj-y +=3D intel-txt.o obj-y +=3D io_apic.o obj-$(CONFIG_LIVEPATCH) +=3D livepatch.o obj-y +=3D msi.o diff --git a/xen/arch/x86/include/asm/intel-txt.h b/xen/arch/x86/include/as= m/intel-txt.h index 122b4293ea..ad3c41d86c 100644 --- a/xen/arch/x86/include/asm/intel-txt.h +++ b/xen/arch/x86/include/asm/intel-txt.h @@ -420,6 +420,12 @@ static inline void txt_verify_pmr_ranges( */ } =20 +/* Prepares for accesses to TXT-specific memory. */ +void txt_map_mem_regions(void); + +/* Marks TXT-specific memory as used to avoid its corruption. */ +void txt_reserve_mem_regions(void); + #endif /* __ASSEMBLY__ */ =20 #endif /* X86_INTEL_TXT_H */ diff --git a/xen/arch/x86/include/asm/mm.h b/xen/arch/x86/include/asm/mm.h index d6e80db71c..91fa95cd90 100644 --- a/xen/arch/x86/include/asm/mm.h +++ b/xen/arch/x86/include/asm/mm.h @@ -106,6 +106,9 @@ #define _PGC_need_scrub _PGC_allocated #define PGC_need_scrub PGC_allocated =20 +/* 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/include/asm/slaunch.h b/xen/arch/x86/include/asm/= slaunch.h index df42defd92..7891d60035 100644 --- a/xen/arch/x86/include/asm/slaunch.h +++ b/xen/arch/x86/include/asm/slaunch.h @@ -7,6 +7,7 @@ #ifndef X86_SLAUNCH_H #define X86_SLAUNCH_H =20 +#include #include =20 /* Indicates an active Secure Launch boot. */ @@ -18,9 +19,52 @@ extern bool slaunch_active; */ extern uint32_t slaunch_slrt; =20 +/* + * evt_log is assigned a physical address and the caller must map it to + * virtual, if needed. + */ +static inline void find_evt_log(const struct slr_table *slrt, void **evt_l= og, + uint32_t *evt_log_size) +{ + const struct slr_entry_log_info *log_info; + + log_info =3D (const struct slr_entry_log_info *) + slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_LOG_INFO); + if ( log_info !=3D NULL ) + { + *evt_log =3D _p(log_info->addr); + *evt_log_size =3D log_info->size; + } + else + { + *evt_log =3D NULL; + *evt_log_size =3D 0; + } +} + /* * Retrieves pointer to SLRT. Checks table's validity and maps it as nece= ssary. */ struct slr_table *slaunch_get_slrt(void); =20 +/* + * Prepares for accesses to essential data structures setup by boot enviro= nment. + */ +void slaunch_map_mem_regions(void); + +/* Marks regions of memory as used to avoid their corruption. */ +void slaunch_reserve_mem_regions(void); + +/* + * This helper function is used to map memory using L2 page tables by alig= ning + * 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 by the = code + * that accesses DRTM-related memory soon after which Xen rebuilds memory = maps, + * effectively dropping all existing mappings. + */ +int slaunch_map_l2(unsigned long paddr, unsigned long size); + #endif /* X86_SLAUNCH_H */ diff --git a/xen/arch/x86/intel-txt.c b/xen/arch/x86/intel-txt.c new file mode 100644 index 0000000000..163383b262 --- /dev/null +++ b/xen/arch/x86/intel-txt.c @@ -0,0 +1,113 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * Copyright (c) 2022-2025 3mdeb Sp. z o.o. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +static uint64_t __initdata txt_heap_base, txt_heap_size; + +void __init txt_map_mem_regions(void) +{ + int rc; + + rc =3D slaunch_map_l2(TXT_PRIV_CONFIG_REGS_BASE, TXT_CONFIG_SPACE_SIZE= ); + BUG_ON(rc !=3D 0); + + txt_heap_base =3D txt_read(TXTCR_HEAP_BASE); + BUG_ON(txt_heap_base =3D=3D 0); + + txt_heap_size =3D txt_read(TXTCR_HEAP_SIZE); + BUG_ON(txt_heap_size =3D=3D 0); + + rc =3D slaunch_map_l2(txt_heap_base, txt_heap_size); + BUG_ON(rc !=3D 0); +} + +/* Mark RAM region as RESERVED if it isn't marked that way already. */ +static int __init mark_ram_as(struct e820map *map, uint64_t start, + uint64_t end, uint32_t type) +{ + unsigned int i; + uint32_t from_type =3D E820_RAM; + + for ( i =3D 0; i < map->nr_map; i++ ) + { + uint64_t rs =3D map->map[i].addr; + uint64_t re =3D rs + map->map[i].size; + + /* The entry includes the range. */ + if ( start >=3D rs && end <=3D re ) + break; + + /* The entry intersects the range. */ + if ( end > rs && start < re ) + { + /* Fatal failure. */ + return 0; + } + } + + /* + * If the range is not included by any entry and no entry intersects i= t, + * then it's not listed in the memory map. Consider this case as a su= ccess + * since we're only preventing RAM from being used and unlisted range = should + * not be used. + */ + if ( i =3D=3D map->nr_map ) + return 1; + + /* + * e820_change_range_type() fails if the range is already marked with = the + * desired type. Don't consider it an error if firmware has done it f= or us. + */ + if ( map->map[i].type =3D=3D type ) + return 1; + + /* E820_ACPI or E820_NVS are really unexpected, but others are fine. */ + if ( map->map[i].type =3D=3D E820_RESERVED || + map->map[i].type =3D=3D E820_UNUSABLE ) + from_type =3D map->map[i].type; + + return e820_change_range_type(map, start, end, from_type, type); +} + +void __init txt_reserve_mem_regions(void) +{ + int rc; + uint64_t sinit_base, sinit_size; + + /* TXT Heap */ + BUG_ON(txt_heap_base =3D=3D 0); + printk("SLAUNCH: reserving TXT heap (%#lx - %#lx)\n", txt_heap_base, + txt_heap_base + txt_heap_size); + rc =3D mark_ram_as(&e820_raw, txt_heap_base, txt_heap_base + txt_heap_= size, + E820_RESERVED); + BUG_ON(rc =3D=3D 0); + + sinit_base =3D txt_read(TXTCR_SINIT_BASE); + BUG_ON(sinit_base =3D=3D 0); + + sinit_size =3D txt_read(TXTCR_SINIT_SIZE); + BUG_ON(sinit_size =3D=3D 0); + + /* SINIT */ + printk("SLAUNCH: reserving SINIT memory (%#lx - %#lx)\n", sinit_base, + sinit_base + sinit_size); + rc =3D mark_ram_as(&e820_raw, sinit_base, sinit_base + sinit_size, + E820_RESERVED); + BUG_ON(rc =3D=3D 0); + + /* TXT Private Space */ + rc =3D mark_ram_as(&e820_raw, TXT_PRIV_CONFIG_REGS_BASE, + TXT_PRIV_CONFIG_REGS_BASE + TXT_CONFIG_SPACE_SIZE, + E820_UNUSABLE); + BUG_ON(rc =3D=3D 0); +} diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 1f5cb67bd0..e4638acd12 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -1087,9 +1088,6 @@ static struct domain *__init create_dom0(struct boot_= info *bi) return d; } =20 -/* How much of the directmap is prebuilt at compile time. */ -#define PREBUILT_MAP_LIMIT (1 << L2_PAGETABLE_SHIFT) - void asmlinkage __init noreturn __start_xen(void) { const char *memmap_type =3D NULL; @@ -1425,6 +1423,12 @@ void asmlinkage __init noreturn __start_xen(void) #endif } =20 + if ( slaunch_active ) + { + slaunch_map_mem_regions(); + slaunch_reserve_mem_regions(); + } + /* Sanitise the raw E820 map to produce a final clean version. */ max_page =3D raw_max_page =3D init_e820(memmap_type, &e820_raw); =20 diff --git a/xen/arch/x86/slaunch.c b/xen/arch/x86/slaunch.c index a3e6ab8d71..ac3b43942b 100644 --- a/xen/arch/x86/slaunch.c +++ b/xen/arch/x86/slaunch.c @@ -7,14 +7,18 @@ #include #include #include +#include #include +#include +#include +#include #include =20 /* * These variables are assigned to by the code near Xen's entry point. * * slaunch_active is not __initdata to allow checking for an active Secure - * Launch boot. + * Launch boot at any point. */ bool slaunch_active; uint32_t __initdata slaunch_slrt; /* physical address */ @@ -25,3 +29,95 @@ static void __maybe_unused compile_time_checks(void) { BUILD_BUG_ON(sizeof(slaunch_active) !=3D 1); } + +struct slr_table *__init slaunch_get_slrt(void) +{ + static struct slr_table *slrt; + + if (slrt =3D=3D NULL) { + int rc; + + slrt =3D __va(slaunch_slrt); + + rc =3D slaunch_map_l2(slaunch_slrt, PAGE_SIZE); + BUG_ON(rc !=3D 0); + + if ( slrt->magic !=3D SLR_TABLE_MAGIC ) + panic("SLRT has invalid magic value: %#08x!\n", slrt->magic); + /* XXX: are newer revisions allowed? */ + if ( slrt->revision !=3D SLR_TABLE_REVISION ) + panic("SLRT is of unsupported revision: %#04x!\n", slrt->revis= ion); + if ( slrt->architecture !=3D 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 ) + { + rc =3D slaunch_map_l2(slaunch_slrt, slrt->size); + BUG_ON(rc !=3D 0); + } + } + + return slrt; +} + +void __init slaunch_map_mem_regions(void) +{ + void *evt_log_addr; + uint32_t evt_log_size; + + /* Vendor-specific part. */ + txt_map_mem_regions(); + + find_evt_log(slaunch_get_slrt(), &evt_log_addr, &evt_log_size); + if ( evt_log_addr !=3D NULL ) + { + int rc =3D slaunch_map_l2((uintptr_t)evt_log_addr, evt_log_size); + BUG_ON(rc !=3D 0); + } +} + +void __init slaunch_reserve_mem_regions(void) +{ + int rc; + + void *evt_log_addr; + uint32_t evt_log_size; + + /* Vendor-specific part. */ + txt_reserve_mem_regions(); + + find_evt_log(slaunch_get_slrt(), &evt_log_addr, &evt_log_size); + if ( evt_log_addr !=3D NULL ) + { + printk("SLAUNCH: reserving event log (%#lx - %#lx)\n", + (uint64_t)evt_log_addr, + (uint64_t)evt_log_addr + evt_log_size); + rc =3D reserve_e820_ram(&e820_raw, (uint64_t)evt_log_addr, + (uint64_t)evt_log_addr + evt_log_size); + BUG_ON(rc =3D=3D 0); + } +} + +int __init slaunch_map_l2(unsigned long paddr, unsigned long size) +{ + unsigned long aligned_paddr =3D paddr & ~((1ULL << L2_PAGETABLE_SHIFT)= - 1); + unsigned long pages =3D ((paddr + size) - aligned_paddr); + pages =3D ROUNDUP(pages, 1ULL << L2_PAGETABLE_SHIFT) >> PAGE_SHIFT; + + if ( aligned_paddr + pages * PAGE_SIZE <=3D PREBUILT_MAP_LIMIT ) + return 0; + + if ( aligned_paddr < PREBUILT_MAP_LIMIT ) + { + pages -=3D (PREBUILT_MAP_LIMIT - aligned_paddr) >> PAGE_SHIFT; + aligned_paddr =3D PREBUILT_MAP_LIMIT; + } + + return map_pages_to_xen((uintptr_t)__va(aligned_paddr), + maddr_to_mfn(aligned_paddr), + pages, PAGE_HYPERVISOR); +} --=20 2.49.0