Skip to content

Commit 3a755eb

Browse files
committed
Merge tag 'x86_tdx_for_v5.19_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull Intel TDX support from Borislav Petkov: "Intel Trust Domain Extensions (TDX) support. This is the Intel version of a confidential computing solution called Trust Domain Extensions (TDX). This series adds support to run the kernel as part of a TDX guest. It provides similar guest protections to AMD's SEV-SNP like guest memory and register state encryption, memory integrity protection and a lot more. Design-wise, it differs from AMD's solution considerably: it uses a software module which runs in a special CPU mode called (Secure Arbitration Mode) SEAM. As the name suggests, this module serves as sort of an arbiter which the confidential guest calls for services it needs during its lifetime. Just like AMD's SNP set, this series reworks and streamlines certain parts of x86 arch code so that this feature can be properly accomodated" * tag 'x86_tdx_for_v5.19_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (34 commits) x86/tdx: Fix RETs in TDX asm x86/tdx: Annotate a noreturn function x86/mm: Fix spacing within memory encryption features message x86/kaslr: Fix build warning in KASLR code in boot stub Documentation/x86: Document TDX kernel architecture ACPICA: Avoid cache flush inside virtual machines x86/tdx/ioapic: Add shared bit for IOAPIC base address x86/mm: Make DMA memory shared for TD guest x86/mm/cpa: Add support for TDX shared memory x86/tdx: Make pages shared in ioremap() x86/topology: Disable CPU online/offline control for TDX guests x86/boot: Avoid #VE during boot for TDX platforms x86/boot: Set CR0.NE early and keep it set during the boot x86/acpi/x86/boot: Add multiprocessor wake-up support x86/boot: Add a trampoline for booting APs via firmware handoff x86/tdx: Wire up KVM hypercalls x86/tdx: Port I/O: Add early boot support x86/tdx: Port I/O: Add runtime hypercalls x86/boot: Port I/O: Add decompression-time support for TDX x86/boot: Port I/O: Allow to hook up alternative helpers ...
2 parents 5b82826 + c796f02 commit 3a755eb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+2071
-120
lines changed

Documentation/x86/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ x86-specific Documentation
2626
intel_txt
2727
amd-memory-encryption
2828
amd_hsmp
29+
tdx
2930
pti
3031
mds
3132
microcode

Documentation/x86/tdx.rst

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
.. SPDX-License-Identifier: GPL-2.0
2+
3+
=====================================
4+
Intel Trust Domain Extensions (TDX)
5+
=====================================
6+
7+
Intel's Trust Domain Extensions (TDX) protect confidential guest VMs from
8+
the host and physical attacks by isolating the guest register state and by
9+
encrypting the guest memory. In TDX, a special module running in a special
10+
mode sits between the host and the guest and manages the guest/host
11+
separation.
12+
13+
Since the host cannot directly access guest registers or memory, much
14+
normal functionality of a hypervisor must be moved into the guest. This is
15+
implemented using a Virtualization Exception (#VE) that is handled by the
16+
guest kernel. A #VE is handled entirely inside the guest kernel, but some
17+
require the hypervisor to be consulted.
18+
19+
TDX includes new hypercall-like mechanisms for communicating from the
20+
guest to the hypervisor or the TDX module.
21+
22+
New TDX Exceptions
23+
==================
24+
25+
TDX guests behave differently from bare-metal and traditional VMX guests.
26+
In TDX guests, otherwise normal instructions or memory accesses can cause
27+
#VE or #GP exceptions.
28+
29+
Instructions marked with an '*' conditionally cause exceptions. The
30+
details for these instructions are discussed below.
31+
32+
Instruction-based #VE
33+
---------------------
34+
35+
- Port I/O (INS, OUTS, IN, OUT)
36+
- HLT
37+
- MONITOR, MWAIT
38+
- WBINVD, INVD
39+
- VMCALL
40+
- RDMSR*,WRMSR*
41+
- CPUID*
42+
43+
Instruction-based #GP
44+
---------------------
45+
46+
- All VMX instructions: INVEPT, INVVPID, VMCLEAR, VMFUNC, VMLAUNCH,
47+
VMPTRLD, VMPTRST, VMREAD, VMRESUME, VMWRITE, VMXOFF, VMXON
48+
- ENCLS, ENCLU
49+
- GETSEC
50+
- RSM
51+
- ENQCMD
52+
- RDMSR*,WRMSR*
53+
54+
RDMSR/WRMSR Behavior
55+
--------------------
56+
57+
MSR access behavior falls into three categories:
58+
59+
- #GP generated
60+
- #VE generated
61+
- "Just works"
62+
63+
In general, the #GP MSRs should not be used in guests. Their use likely
64+
indicates a bug in the guest. The guest may try to handle the #GP with a
65+
hypercall but it is unlikely to succeed.
66+
67+
The #VE MSRs are typically able to be handled by the hypervisor. Guests
68+
can make a hypercall to the hypervisor to handle the #VE.
69+
70+
The "just works" MSRs do not need any special guest handling. They might
71+
be implemented by directly passing through the MSR to the hardware or by
72+
trapping and handling in the TDX module. Other than possibly being slow,
73+
these MSRs appear to function just as they would on bare metal.
74+
75+
CPUID Behavior
76+
--------------
77+
78+
For some CPUID leaves and sub-leaves, the virtualized bit fields of CPUID
79+
return values (in guest EAX/EBX/ECX/EDX) are configurable by the
80+
hypervisor. For such cases, the Intel TDX module architecture defines two
81+
virtualization types:
82+
83+
- Bit fields for which the hypervisor controls the value seen by the guest
84+
TD.
85+
86+
- Bit fields for which the hypervisor configures the value such that the
87+
guest TD either sees their native value or a value of 0. For these bit
88+
fields, the hypervisor can mask off the native values, but it can not
89+
turn *on* values.
90+
91+
A #VE is generated for CPUID leaves and sub-leaves that the TDX module does
92+
not know how to handle. The guest kernel may ask the hypervisor for the
93+
value with a hypercall.
94+
95+
#VE on Memory Accesses
96+
======================
97+
98+
There are essentially two classes of TDX memory: private and shared.
99+
Private memory receives full TDX protections. Its content is protected
100+
against access from the hypervisor. Shared memory is expected to be
101+
shared between guest and hypervisor and does not receive full TDX
102+
protections.
103+
104+
A TD guest is in control of whether its memory accesses are treated as
105+
private or shared. It selects the behavior with a bit in its page table
106+
entries. This helps ensure that a guest does not place sensitive
107+
information in shared memory, exposing it to the untrusted hypervisor.
108+
109+
#VE on Shared Memory
110+
--------------------
111+
112+
Access to shared mappings can cause a #VE. The hypervisor ultimately
113+
controls whether a shared memory access causes a #VE, so the guest must be
114+
careful to only reference shared pages it can safely handle a #VE. For
115+
instance, the guest should be careful not to access shared memory in the
116+
#VE handler before it reads the #VE info structure (TDG.VP.VEINFO.GET).
117+
118+
Shared mapping content is entirely controlled by the hypervisor. The guest
119+
should only use shared mappings for communicating with the hypervisor.
120+
Shared mappings must never be used for sensitive memory content like kernel
121+
stacks. A good rule of thumb is that hypervisor-shared memory should be
122+
treated the same as memory mapped to userspace. Both the hypervisor and
123+
userspace are completely untrusted.
124+
125+
MMIO for virtual devices is implemented as shared memory. The guest must
126+
be careful not to access device MMIO regions unless it is also prepared to
127+
handle a #VE.
128+
129+
#VE on Private Pages
130+
--------------------
131+
132+
An access to private mappings can also cause a #VE. Since all kernel
133+
memory is also private memory, the kernel might theoretically need to
134+
handle a #VE on arbitrary kernel memory accesses. This is not feasible, so
135+
TDX guests ensure that all guest memory has been "accepted" before memory
136+
is used by the kernel.
137+
138+
A modest amount of memory (typically 512M) is pre-accepted by the firmware
139+
before the kernel runs to ensure that the kernel can start up without
140+
being subjected to a #VE.
141+
142+
The hypervisor is permitted to unilaterally move accepted pages to a
143+
"blocked" state. However, if it does this, page access will not generate a
144+
#VE. It will, instead, cause a "TD Exit" where the hypervisor is required
145+
to handle the exception.
146+
147+
Linux #VE handler
148+
=================
149+
150+
Just like page faults or #GP's, #VE exceptions can be either handled or be
151+
fatal. Typically, an unhandled userspace #VE results in a SIGSEGV.
152+
An unhandled kernel #VE results in an oops.
153+
154+
Handling nested exceptions on x86 is typically nasty business. A #VE
155+
could be interrupted by an NMI which triggers another #VE and hilarity
156+
ensues. The TDX #VE architecture anticipated this scenario and includes a
157+
feature to make it slightly less nasty.
158+
159+
During #VE handling, the TDX module ensures that all interrupts (including
160+
NMIs) are blocked. The block remains in place until the guest makes a
161+
TDG.VP.VEINFO.GET TDCALL. This allows the guest to control when interrupts
162+
or a new #VE can be delivered.
163+
164+
However, the guest kernel must still be careful to avoid potential
165+
#VE-triggering actions (discussed above) while this block is in place.
166+
While the block is in place, any #VE is elevated to a double fault (#DF)
167+
which is not recoverable.
168+
169+
MMIO handling
170+
=============
171+
172+
In non-TDX VMs, MMIO is usually implemented by giving a guest access to a
173+
mapping which will cause a VMEXIT on access, and then the hypervisor
174+
emulates the access. That is not possible in TDX guests because VMEXIT
175+
will expose the register state to the host. TDX guests don't trust the host
176+
and can't have their state exposed to the host.
177+
178+
In TDX, MMIO regions typically trigger a #VE exception in the guest. The
179+
guest #VE handler then emulates the MMIO instruction inside the guest and
180+
converts it into a controlled TDCALL to the host, rather than exposing
181+
guest state to the host.
182+
183+
MMIO addresses on x86 are just special physical addresses. They can
184+
theoretically be accessed with any instruction that accesses memory.
185+
However, the kernel instruction decoding method is limited. It is only
186+
designed to decode instructions like those generated by io.h macros.
187+
188+
MMIO access via other means (like structure overlays) may result in an
189+
oops.
190+
191+
Shared Memory Conversions
192+
=========================
193+
194+
All TDX guest memory starts out as private at boot. This memory can not
195+
be accessed by the hypervisor. However, some kernel users like device
196+
drivers might have a need to share data with the hypervisor. To do this,
197+
memory must be converted between shared and private. This can be
198+
accomplished using some existing memory encryption helpers:
199+
200+
* set_memory_decrypted() converts a range of pages to shared.
201+
* set_memory_encrypted() converts memory back to private.
202+
203+
Device drivers are the primary user of shared memory, but there's no need
204+
to touch every driver. DMA buffers and ioremap() do the conversions
205+
automatically.
206+
207+
TDX uses SWIOTLB for most DMA allocations. The SWIOTLB buffer is
208+
converted to shared on boot.
209+
210+
For coherent DMA allocation, the DMA buffer gets converted on the
211+
allocation. Check force_dma_unencrypted() for details.
212+
213+
References
214+
==========
215+
216+
TDX reference material is collected here:
217+
218+
https://www.intel.com/content/www/us/en/developer/articles/technical/intel-trust-domain-extensions.html

arch/x86/Kconfig

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,21 @@ config ACRN_GUEST
878878
IOT with small footprint and real-time features. More details can be
879879
found in https://projectacrn.org/.
880880

881+
config INTEL_TDX_GUEST
882+
bool "Intel TDX (Trust Domain Extensions) - Guest Support"
883+
depends on X86_64 && CPU_SUP_INTEL
884+
depends on X86_X2APIC
885+
select ARCH_HAS_CC_PLATFORM
886+
select X86_MEM_ENCRYPT
887+
select X86_MCE
888+
help
889+
Support running as a guest under Intel TDX. Without this support,
890+
the guest kernel can not boot or run under TDX.
891+
TDX includes memory encryption and integrity capabilities
892+
which protect the confidentiality and integrity of guest
893+
memory contents and CPU state. TDX guests are protected from
894+
some attacks from the VMM.
895+
881896
endif #HYPERVISOR_GUEST
882897

883898
source "arch/x86/Kconfig.cpu"

arch/x86/boot/boot.h

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "bitops.h"
2727
#include "ctype.h"
2828
#include "cpuflags.h"
29+
#include "io.h"
2930

3031
/* Useful macros */
3132
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
@@ -35,44 +36,10 @@ extern struct boot_params boot_params;
3536

3637
#define cpu_relax() asm volatile("rep; nop")
3738

38-
/* Basic port I/O */
39-
static inline void outb(u8 v, u16 port)
40-
{
41-
asm volatile("outb %0,%1" : : "a" (v), "dN" (port));
42-
}
43-
static inline u8 inb(u16 port)
44-
{
45-
u8 v;
46-
asm volatile("inb %1,%0" : "=a" (v) : "dN" (port));
47-
return v;
48-
}
49-
50-
static inline void outw(u16 v, u16 port)
51-
{
52-
asm volatile("outw %0,%1" : : "a" (v), "dN" (port));
53-
}
54-
static inline u16 inw(u16 port)
55-
{
56-
u16 v;
57-
asm volatile("inw %1,%0" : "=a" (v) : "dN" (port));
58-
return v;
59-
}
60-
61-
static inline void outl(u32 v, u16 port)
62-
{
63-
asm volatile("outl %0,%1" : : "a" (v), "dN" (port));
64-
}
65-
static inline u32 inl(u16 port)
66-
{
67-
u32 v;
68-
asm volatile("inl %1,%0" : "=a" (v) : "dN" (port));
69-
return v;
70-
}
71-
7239
static inline void io_delay(void)
7340
{
7441
const u16 DELAY_PORT = 0x80;
75-
asm volatile("outb %%al,%0" : : "dN" (DELAY_PORT));
42+
outb(0, DELAY_PORT);
7643
}
7744

7845
/* These functions are used to reference data in other segments. */

arch/x86/boot/compressed/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ ifdef CONFIG_X86_64
101101
endif
102102

103103
vmlinux-objs-$(CONFIG_ACPI) += $(obj)/acpi.o
104+
vmlinux-objs-$(CONFIG_INTEL_TDX_GUEST) += $(obj)/tdx.o $(obj)/tdcall.o
104105

105106
vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_thunk_$(BITS).o
106107
vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o

arch/x86/boot/compressed/head_64.S

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ SYM_FUNC_START(startup_32)
289289
pushl %eax
290290

291291
/* Enter paged protected Mode, activating Long Mode */
292-
movl $(X86_CR0_PG | X86_CR0_PE), %eax /* Enable Paging and Protected mode */
292+
movl $CR0_STATE, %eax
293293
movl %eax, %cr0
294294

295295
/* Jump from 32bit compatibility mode into 64bit mode. */
@@ -649,12 +649,28 @@ SYM_CODE_START(trampoline_32bit_src)
649649
movl $MSR_EFER, %ecx
650650
rdmsr
651651
btsl $_EFER_LME, %eax
652+
/* Avoid writing EFER if no change was made (for TDX guest) */
653+
jc 1f
652654
wrmsr
653-
popl %edx
655+
1: popl %edx
654656
popl %ecx
655657

658+
#ifdef CONFIG_X86_MCE
659+
/*
660+
* Preserve CR4.MCE if the kernel will enable #MC support.
661+
* Clearing MCE may fault in some environments (that also force #MC
662+
* support). Any machine check that occurs before #MC support is fully
663+
* configured will crash the system regardless of the CR4.MCE value set
664+
* here.
665+
*/
666+
movl %cr4, %eax
667+
andl $X86_CR4_MCE, %eax
668+
#else
669+
movl $0, %eax
670+
#endif
671+
656672
/* Enable PAE and LA57 (if required) paging modes */
657-
movl $X86_CR4_PAE, %eax
673+
orl $X86_CR4_PAE, %eax
658674
testl %edx, %edx
659675
jz 1f
660676
orl $X86_CR4_LA57, %eax
@@ -668,8 +684,9 @@ SYM_CODE_START(trampoline_32bit_src)
668684
pushl $__KERNEL_CS
669685
pushl %eax
670686

671-
/* Enable paging again */
672-
movl $(X86_CR0_PG | X86_CR0_PE), %eax
687+
/* Enable paging again. */
688+
movl %cr0, %eax
689+
btsl $X86_CR0_PG_BIT, %eax
673690
movl %eax, %cr0
674691

675692
lret

arch/x86/boot/compressed/misc.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ void *memmove(void *dest, const void *src, size_t n);
4848
*/
4949
struct boot_params *boot_params;
5050

51+
struct port_io_ops pio_ops;
52+
5153
memptr free_mem_ptr;
5254
memptr free_mem_end_ptr;
5355

@@ -374,6 +376,16 @@ asmlinkage __visible void *extract_kernel(void *rmode, memptr heap,
374376
lines = boot_params->screen_info.orig_video_lines;
375377
cols = boot_params->screen_info.orig_video_cols;
376378

379+
init_default_io_ops();
380+
381+
/*
382+
* Detect TDX guest environment.
383+
*
384+
* It has to be done before console_init() in order to use
385+
* paravirtualized port I/O operations if needed.
386+
*/
387+
early_tdx_detect();
388+
377389
console_init();
378390

379391
/*

0 commit comments

Comments
 (0)