mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 21:38:32 +08:00
- Add support managing TDX host hardware
-----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEV76QKkVc4xCGURexaDWVMHDJkrAFAmWfCRQACgkQaDWVMHDJ krDUqQ//VCvkpf0mAbYDJa1oTXFW8O5cVTusBtPi8k7cFbtjQpjno/9AqKol+sK8 AKg+y5iHHl7QJmDmEcpS+O9OBbmFOpvDzm3QZhk8RkWS5pe0B108dnINYtS0eP9R MkzZwfrI2yC6NX4hvHGdD8WGHjrt+oxY0bojehX87JZsyRU+xqc/g1OO7a5bUPQe 3Ip0kKiCeqFv0y+Q1pFMEd9RdZ8XxqzUHCJT3hfgZ6FajJ2eVy6jNrPOm6LozycB eOtYYNapSgw3k/WhJCOYWHX7kePXibLxBRONLpi6P3U6pMVk4n8wrgl7qPtdW1Qx nR2UHX5P6eFkxNCuU1BzvmPBROe37C51MFVw29eRnigvuX3j/vfCH1+17xQOVKVv 5JyxYA0rJWqoOz6mX7YaNJHlmrxHzeKXudICyOFuu1j5c8CuGjh8NQsOSCq16XfZ hPzfYDUS8I7/kHYQPJlnB+kF9pmbyjTM70h74I8D6ZWvXESHJZt+TYPyWfkBXP/P L9Pwx1onAyoBApGxCWuvgGTLonzNredgYG4ABbqhUqxqncJS9M7Y/yJa+f+3SOkR T6LxoByuDVld5cIfbOzRwIaRezZDe/NL7rkHm/DWo98OaV3zILsr20Hx1lPZ1Vce ryZ9lCdZGGxm2jmpzr/VymPQz/E+ezahRHE1+F3su8jpCU41txg= =1EJI -----END PGP SIGNATURE----- Merge tag 'x86_tdx_for_6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull x86 TDX updates from Dave Hansen: "This contains the initial support for host-side TDX support so that KVM can run TDX-protected guests. This does not include the actual KVM-side support which will come from the KVM folks. The TDX host interactions with kexec also needs to be ironed out before this is ready for prime time, so this code is currently Kconfig'd off when kexec is on. The majority of the code here is the kernel telling the TDX module which memory to protect and handing some additional memory over to it to use to store TDX module metadata. That sounds pretty simple, but the TDX architecture is rather flexible and it takes quite a bit of back-and-forth to say, "just protect all memory, please." There is also some code tacked on near the end of the series to handle a hardware erratum. The erratum can make software bugs such as a kernel write to TDX-protected memory cause a machine check and masquerade as a real hardware failure. The erratum handling watches out for these and tries to provide nicer user errors" * tag 'x86_tdx_for_6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (21 commits) x86/virt/tdx: Make TDX host depend on X86_MCE x86/virt/tdx: Disable TDX host support when kexec is enabled Documentation/x86: Add documentation for TDX host support x86/mce: Differentiate real hardware #MCs from TDX erratum ones x86/cpu: Detect TDX partial write machine check erratum x86/virt/tdx: Handle TDX interaction with sleep and hibernation x86/virt/tdx: Initialize all TDMRs x86/virt/tdx: Configure global KeyID on all packages x86/virt/tdx: Configure TDX module with the TDMRs and global KeyID x86/virt/tdx: Designate reserved areas for all TDMRs x86/virt/tdx: Allocate and set up PAMTs for TDMRs x86/virt/tdx: Fill out TDMRs to cover all TDX memory regions x86/virt/tdx: Add placeholder to construct TDMRs to cover all TDX memory regions x86/virt/tdx: Get module global metadata for module initialization x86/virt/tdx: Use all system memory when initializing TDX module as TDX memory x86/virt/tdx: Add skeleton to enable TDX on demand x86/virt/tdx: Add SEAMCALL error printing for module initialization x86/virt/tdx: Handle SEAMCALL no entropy error in common code x86/virt/tdx: Make INTEL_TDX_HOST depend on X86_X2APIC x86/virt/tdx: Define TDX supported page sizes as macros ...
This commit is contained in:
commit
b4442cadca
@ -10,6 +10,191 @@ encrypting the guest memory. In TDX, a special module running in a special
|
||||
mode sits between the host and the guest and manages the guest/host
|
||||
separation.
|
||||
|
||||
TDX Host Kernel Support
|
||||
=======================
|
||||
|
||||
TDX introduces a new CPU mode called Secure Arbitration Mode (SEAM) and
|
||||
a new isolated range pointed by the SEAM Ranger Register (SEAMRR). A
|
||||
CPU-attested software module called 'the TDX module' runs inside the new
|
||||
isolated range to provide the functionalities to manage and run protected
|
||||
VMs.
|
||||
|
||||
TDX also leverages Intel Multi-Key Total Memory Encryption (MKTME) to
|
||||
provide crypto-protection to the VMs. TDX reserves part of MKTME KeyIDs
|
||||
as TDX private KeyIDs, which are only accessible within the SEAM mode.
|
||||
BIOS is responsible for partitioning legacy MKTME KeyIDs and TDX KeyIDs.
|
||||
|
||||
Before the TDX module can be used to create and run protected VMs, it
|
||||
must be loaded into the isolated range and properly initialized. The TDX
|
||||
architecture doesn't require the BIOS to load the TDX module, but the
|
||||
kernel assumes it is loaded by the BIOS.
|
||||
|
||||
TDX boot-time detection
|
||||
-----------------------
|
||||
|
||||
The kernel detects TDX by detecting TDX private KeyIDs during kernel
|
||||
boot. Below dmesg shows when TDX is enabled by BIOS::
|
||||
|
||||
[..] virt/tdx: BIOS enabled: private KeyID range: [16, 64)
|
||||
|
||||
TDX module initialization
|
||||
---------------------------------------
|
||||
|
||||
The kernel talks to the TDX module via the new SEAMCALL instruction. The
|
||||
TDX module implements SEAMCALL leaf functions to allow the kernel to
|
||||
initialize it.
|
||||
|
||||
If the TDX module isn't loaded, the SEAMCALL instruction fails with a
|
||||
special error. In this case the kernel fails the module initialization
|
||||
and reports the module isn't loaded::
|
||||
|
||||
[..] virt/tdx: module not loaded
|
||||
|
||||
Initializing the TDX module consumes roughly ~1/256th system RAM size to
|
||||
use it as 'metadata' for the TDX memory. It also takes additional CPU
|
||||
time to initialize those metadata along with the TDX module itself. Both
|
||||
are not trivial. The kernel initializes the TDX module at runtime on
|
||||
demand.
|
||||
|
||||
Besides initializing the TDX module, a per-cpu initialization SEAMCALL
|
||||
must be done on one cpu before any other SEAMCALLs can be made on that
|
||||
cpu.
|
||||
|
||||
The kernel provides two functions, tdx_enable() and tdx_cpu_enable() to
|
||||
allow the user of TDX to enable the TDX module and enable TDX on local
|
||||
cpu respectively.
|
||||
|
||||
Making SEAMCALL requires VMXON has been done on that CPU. Currently only
|
||||
KVM implements VMXON. For now both tdx_enable() and tdx_cpu_enable()
|
||||
don't do VMXON internally (not trivial), but depends on the caller to
|
||||
guarantee that.
|
||||
|
||||
To enable TDX, the caller of TDX should: 1) temporarily disable CPU
|
||||
hotplug; 2) do VMXON and tdx_enable_cpu() on all online cpus; 3) call
|
||||
tdx_enable(). For example::
|
||||
|
||||
cpus_read_lock();
|
||||
on_each_cpu(vmxon_and_tdx_cpu_enable());
|
||||
ret = tdx_enable();
|
||||
cpus_read_unlock();
|
||||
if (ret)
|
||||
goto no_tdx;
|
||||
// TDX is ready to use
|
||||
|
||||
And the caller of TDX must guarantee the tdx_cpu_enable() has been
|
||||
successfully done on any cpu before it wants to run any other SEAMCALL.
|
||||
A typical usage is do both VMXON and tdx_cpu_enable() in CPU hotplug
|
||||
online callback, and refuse to online if tdx_cpu_enable() fails.
|
||||
|
||||
User can consult dmesg to see whether the TDX module has been initialized.
|
||||
|
||||
If the TDX module is initialized successfully, dmesg shows something
|
||||
like below::
|
||||
|
||||
[..] virt/tdx: 262668 KBs allocated for PAMT
|
||||
[..] virt/tdx: module initialized
|
||||
|
||||
If the TDX module failed to initialize, dmesg also shows it failed to
|
||||
initialize::
|
||||
|
||||
[..] virt/tdx: module initialization failed ...
|
||||
|
||||
TDX Interaction to Other Kernel Components
|
||||
------------------------------------------
|
||||
|
||||
TDX Memory Policy
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
TDX reports a list of "Convertible Memory Region" (CMR) to tell the
|
||||
kernel which memory is TDX compatible. The kernel needs to build a list
|
||||
of memory regions (out of CMRs) as "TDX-usable" memory and pass those
|
||||
regions to the TDX module. Once this is done, those "TDX-usable" memory
|
||||
regions are fixed during module's lifetime.
|
||||
|
||||
To keep things simple, currently the kernel simply guarantees all pages
|
||||
in the page allocator are TDX memory. Specifically, the kernel uses all
|
||||
system memory in the core-mm "at the time of TDX module initialization"
|
||||
as TDX memory, and in the meantime, refuses to online any non-TDX-memory
|
||||
in the memory hotplug.
|
||||
|
||||
Physical Memory Hotplug
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Note TDX assumes convertible memory is always physically present during
|
||||
machine's runtime. A non-buggy BIOS should never support hot-removal of
|
||||
any convertible memory. This implementation doesn't handle ACPI memory
|
||||
removal but depends on the BIOS to behave correctly.
|
||||
|
||||
CPU Hotplug
|
||||
~~~~~~~~~~~
|
||||
|
||||
TDX module requires the per-cpu initialization SEAMCALL must be done on
|
||||
one cpu before any other SEAMCALLs can be made on that cpu. The kernel
|
||||
provides tdx_cpu_enable() to let the user of TDX to do it when the user
|
||||
wants to use a new cpu for TDX task.
|
||||
|
||||
TDX doesn't support physical (ACPI) CPU hotplug. During machine boot,
|
||||
TDX verifies all boot-time present logical CPUs are TDX compatible before
|
||||
enabling TDX. A non-buggy BIOS should never support hot-add/removal of
|
||||
physical CPU. Currently the kernel doesn't handle physical CPU hotplug,
|
||||
but depends on the BIOS to behave correctly.
|
||||
|
||||
Note TDX works with CPU logical online/offline, thus the kernel still
|
||||
allows to offline logical CPU and online it again.
|
||||
|
||||
Kexec()
|
||||
~~~~~~~
|
||||
|
||||
TDX host support currently lacks the ability to handle kexec. For
|
||||
simplicity only one of them can be enabled in the Kconfig. This will be
|
||||
fixed in the future.
|
||||
|
||||
Erratum
|
||||
~~~~~~~
|
||||
|
||||
The first few generations of TDX hardware have an erratum. A partial
|
||||
write to a TDX private memory cacheline will silently "poison" the
|
||||
line. Subsequent reads will consume the poison and generate a machine
|
||||
check.
|
||||
|
||||
A partial write is a memory write where a write transaction of less than
|
||||
cacheline lands at the memory controller. The CPU does these via
|
||||
non-temporal write instructions (like MOVNTI), or through UC/WC memory
|
||||
mappings. Devices can also do partial writes via DMA.
|
||||
|
||||
Theoretically, a kernel bug could do partial write to TDX private memory
|
||||
and trigger unexpected machine check. What's more, the machine check
|
||||
code will present these as "Hardware error" when they were, in fact, a
|
||||
software-triggered issue. But in the end, this issue is hard to trigger.
|
||||
|
||||
If the platform has such erratum, the kernel prints additional message in
|
||||
machine check handler to tell user the machine check may be caused by
|
||||
kernel bug on TDX private memory.
|
||||
|
||||
Interaction vs S3 and deeper states
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
TDX cannot survive from S3 and deeper states. The hardware resets and
|
||||
disables TDX completely when platform goes to S3 and deeper. Both TDX
|
||||
guests and the TDX module get destroyed permanently.
|
||||
|
||||
The kernel uses S3 for suspend-to-ram, and use S4 and deeper states for
|
||||
hibernation. Currently, for simplicity, the kernel chooses to make TDX
|
||||
mutually exclusive with S3 and hibernation.
|
||||
|
||||
The kernel disables TDX during early boot when hibernation support is
|
||||
available::
|
||||
|
||||
[..] virt/tdx: initialization failed: Hibernation support is enabled
|
||||
|
||||
Add 'nohibernate' kernel command line to disable hibernation in order to
|
||||
use TDX.
|
||||
|
||||
ACPI S3 is disabled during kernel early boot if TDX is enabled. The user
|
||||
needs to turn off TDX in the BIOS in order to use S3.
|
||||
|
||||
TDX Guest Support
|
||||
=================
|
||||
Since the host cannot directly access guest registers or memory, much
|
||||
normal functionality of a hypervisor must be moved into the guest. This is
|
||||
implemented using a Virtualization Exception (#VE) that is handled by the
|
||||
@ -20,7 +205,7 @@ TDX includes new hypercall-like mechanisms for communicating from the
|
||||
guest to the hypervisor or the TDX module.
|
||||
|
||||
New TDX Exceptions
|
||||
==================
|
||||
------------------
|
||||
|
||||
TDX guests behave differently from bare-metal and traditional VMX guests.
|
||||
In TDX guests, otherwise normal instructions or memory accesses can cause
|
||||
@ -30,7 +215,7 @@ Instructions marked with an '*' conditionally cause exceptions. The
|
||||
details for these instructions are discussed below.
|
||||
|
||||
Instruction-based #VE
|
||||
---------------------
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- Port I/O (INS, OUTS, IN, OUT)
|
||||
- HLT
|
||||
@ -41,7 +226,7 @@ Instruction-based #VE
|
||||
- CPUID*
|
||||
|
||||
Instruction-based #GP
|
||||
---------------------
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- All VMX instructions: INVEPT, INVVPID, VMCLEAR, VMFUNC, VMLAUNCH,
|
||||
VMPTRLD, VMPTRST, VMREAD, VMRESUME, VMWRITE, VMXOFF, VMXON
|
||||
@ -52,7 +237,7 @@ Instruction-based #GP
|
||||
- RDMSR*,WRMSR*
|
||||
|
||||
RDMSR/WRMSR Behavior
|
||||
--------------------
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
MSR access behavior falls into three categories:
|
||||
|
||||
@ -73,7 +258,7 @@ trapping and handling in the TDX module. Other than possibly being slow,
|
||||
these MSRs appear to function just as they would on bare metal.
|
||||
|
||||
CPUID Behavior
|
||||
--------------
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
For some CPUID leaves and sub-leaves, the virtualized bit fields of CPUID
|
||||
return values (in guest EAX/EBX/ECX/EDX) are configurable by the
|
||||
@ -93,7 +278,7 @@ not know how to handle. The guest kernel may ask the hypervisor for the
|
||||
value with a hypercall.
|
||||
|
||||
#VE on Memory Accesses
|
||||
======================
|
||||
----------------------
|
||||
|
||||
There are essentially two classes of TDX memory: private and shared.
|
||||
Private memory receives full TDX protections. Its content is protected
|
||||
@ -107,7 +292,7 @@ entries. This helps ensure that a guest does not place sensitive
|
||||
information in shared memory, exposing it to the untrusted hypervisor.
|
||||
|
||||
#VE on Shared Memory
|
||||
--------------------
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Access to shared mappings can cause a #VE. The hypervisor ultimately
|
||||
controls whether a shared memory access causes a #VE, so the guest must be
|
||||
@ -127,7 +312,7 @@ be careful not to access device MMIO regions unless it is also prepared to
|
||||
handle a #VE.
|
||||
|
||||
#VE on Private Pages
|
||||
--------------------
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
An access to private mappings can also cause a #VE. Since all kernel
|
||||
memory is also private memory, the kernel might theoretically need to
|
||||
@ -145,7 +330,7 @@ The hypervisor is permitted to unilaterally move accepted pages to a
|
||||
to handle the exception.
|
||||
|
||||
Linux #VE handler
|
||||
=================
|
||||
-----------------
|
||||
|
||||
Just like page faults or #GP's, #VE exceptions can be either handled or be
|
||||
fatal. Typically, an unhandled userspace #VE results in a SIGSEGV.
|
||||
@ -167,7 +352,7 @@ While the block is in place, any #VE is elevated to a double fault (#DF)
|
||||
which is not recoverable.
|
||||
|
||||
MMIO handling
|
||||
=============
|
||||
-------------
|
||||
|
||||
In non-TDX VMs, MMIO is usually implemented by giving a guest access to a
|
||||
mapping which will cause a VMEXIT on access, and then the hypervisor
|
||||
@ -189,7 +374,7 @@ MMIO access via other means (like structure overlays) may result in an
|
||||
oops.
|
||||
|
||||
Shared Memory Conversions
|
||||
=========================
|
||||
-------------------------
|
||||
|
||||
All TDX guest memory starts out as private at boot. This memory can not
|
||||
be accessed by the hypervisor. However, some kernel users like device
|
||||
|
@ -1969,6 +1969,11 @@ config INTEL_TDX_HOST
|
||||
depends on CPU_SUP_INTEL
|
||||
depends on X86_64
|
||||
depends on KVM_INTEL
|
||||
depends on X86_X2APIC
|
||||
select ARCH_KEEP_MEMBLOCK
|
||||
depends on CONTIG_ALLOC
|
||||
depends on !KEXEC_CORE
|
||||
depends on X86_MCE
|
||||
help
|
||||
Intel Trust Domain Extensions (TDX) protects guest VMs from malicious
|
||||
host and certain physical attacks. This option enables necessary TDX
|
||||
|
@ -22,13 +22,13 @@ static unsigned long try_accept_one(phys_addr_t start, unsigned long len,
|
||||
*/
|
||||
switch (pg_level) {
|
||||
case PG_LEVEL_4K:
|
||||
page_size = 0;
|
||||
page_size = TDX_PS_4K;
|
||||
break;
|
||||
case PG_LEVEL_2M:
|
||||
page_size = 1;
|
||||
page_size = TDX_PS_2M;
|
||||
break;
|
||||
case PG_LEVEL_1G:
|
||||
page_size = 2;
|
||||
page_size = TDX_PS_1G;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
|
@ -198,6 +198,7 @@
|
||||
#define X86_FEATURE_CAT_L3 ( 7*32+ 4) /* Cache Allocation Technology L3 */
|
||||
#define X86_FEATURE_CAT_L2 ( 7*32+ 5) /* Cache Allocation Technology L2 */
|
||||
#define X86_FEATURE_CDP_L3 ( 7*32+ 6) /* Code and Data Prioritization L3 */
|
||||
#define X86_FEATURE_TDX_HOST_PLATFORM ( 7*32+ 7) /* Platform supports being a TDX host */
|
||||
#define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* AMD HW-PState */
|
||||
#define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */
|
||||
#define X86_FEATURE_XCOMPACTED ( 7*32+10) /* "" Use compacted XSTATE (XSAVES or XSAVEC) */
|
||||
@ -499,6 +500,7 @@
|
||||
#define X86_BUG_EIBRS_PBRSB X86_BUG(28) /* EIBRS is vulnerable to Post Barrier RSB Predictions */
|
||||
#define X86_BUG_SMT_RSB X86_BUG(29) /* CPU is vulnerable to Cross-Thread Return Address Predictions */
|
||||
#define X86_BUG_GDS X86_BUG(30) /* CPU is affected by Gather Data Sampling */
|
||||
#define X86_BUG_TDX_PW_MCE X86_BUG(31) /* CPU may incur #MC if non-TD software does partial write to TDX private memory */
|
||||
|
||||
/* BUG word 2 */
|
||||
#define X86_BUG_SRSO X86_BUG(1*32 + 0) /* AMD SRSO bug */
|
||||
|
@ -541,6 +541,9 @@
|
||||
#define MSR_RELOAD_PMC0 0x000014c1
|
||||
#define MSR_RELOAD_FIXED_CTR0 0x00001309
|
||||
|
||||
/* KeyID partitioning between MKTME and TDX */
|
||||
#define MSR_IA32_MKTME_KEYID_PARTITIONING 0x00000087
|
||||
|
||||
/*
|
||||
* AMD64 MSRs. Not complete. See the architecture manual for a more
|
||||
* complete list.
|
||||
|
@ -55,6 +55,12 @@
|
||||
(TDX_RDX | TDX_RBX | TDX_RSI | TDX_RDI | TDX_R8 | TDX_R9 | \
|
||||
TDX_R10 | TDX_R11 | TDX_R12 | TDX_R13 | TDX_R14 | TDX_R15)
|
||||
|
||||
/* TDX supported page sizes from the TDX module ABI. */
|
||||
#define TDX_PS_4K 0
|
||||
#define TDX_PS_2M 1
|
||||
#define TDX_PS_1G 2
|
||||
#define TDX_PS_NR (TDX_PS_1G + 1)
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <linux/compiler_attributes.h>
|
||||
|
@ -24,8 +24,16 @@
|
||||
#define TDX_SEAMCALL_GP (TDX_SW_ERROR | X86_TRAP_GP)
|
||||
#define TDX_SEAMCALL_UD (TDX_SW_ERROR | X86_TRAP_UD)
|
||||
|
||||
/*
|
||||
* TDX module SEAMCALL leaf function error codes
|
||||
*/
|
||||
#define TDX_SUCCESS 0ULL
|
||||
#define TDX_RND_NO_ENTROPY 0x8000020300000000ULL
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <uapi/asm/mce.h>
|
||||
|
||||
/*
|
||||
* Used by the #VE exception handler to gather the #VE exception
|
||||
* info from the TDX module. This is a software only structure
|
||||
@ -83,6 +91,36 @@ static inline long tdx_kvm_hypercall(unsigned int nr, unsigned long p1,
|
||||
u64 __seamcall(u64 fn, struct tdx_module_args *args);
|
||||
u64 __seamcall_ret(u64 fn, struct tdx_module_args *args);
|
||||
u64 __seamcall_saved_ret(u64 fn, struct tdx_module_args *args);
|
||||
void tdx_init(void);
|
||||
|
||||
#include <asm/archrandom.h>
|
||||
|
||||
typedef u64 (*sc_func_t)(u64 fn, struct tdx_module_args *args);
|
||||
|
||||
static inline u64 sc_retry(sc_func_t func, u64 fn,
|
||||
struct tdx_module_args *args)
|
||||
{
|
||||
int retry = RDRAND_RETRY_LOOPS;
|
||||
u64 ret;
|
||||
|
||||
do {
|
||||
ret = func(fn, args);
|
||||
} while (ret == TDX_RND_NO_ENTROPY && --retry);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define seamcall(_fn, _args) sc_retry(__seamcall, (_fn), (_args))
|
||||
#define seamcall_ret(_fn, _args) sc_retry(__seamcall_ret, (_fn), (_args))
|
||||
#define seamcall_saved_ret(_fn, _args) sc_retry(__seamcall_saved_ret, (_fn), (_args))
|
||||
int tdx_cpu_enable(void);
|
||||
int tdx_enable(void);
|
||||
const char *tdx_dump_mce_info(struct mce *m);
|
||||
#else
|
||||
static inline void tdx_init(void) { }
|
||||
static inline int tdx_cpu_enable(void) { return -ENODEV; }
|
||||
static inline int tdx_enable(void) { return -ENODEV; }
|
||||
static inline const char *tdx_dump_mce_info(struct mce *m) { return NULL; }
|
||||
#endif /* CONFIG_INTEL_TDX_HOST */
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
@ -66,6 +66,7 @@
|
||||
#include <asm/set_memory.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/sev.h>
|
||||
#include <asm/tdx.h>
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
@ -1986,6 +1987,7 @@ static __init void identify_boot_cpu(void)
|
||||
setup_cr_pinning();
|
||||
|
||||
tsx_init();
|
||||
tdx_init();
|
||||
lkgs_init();
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,7 @@
|
||||
#include <asm/mce.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/reboot.h>
|
||||
#include <asm/tdx.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@ -229,12 +230,20 @@ static void wait_for_panic(void)
|
||||
panic("Panicing machine check CPU died");
|
||||
}
|
||||
|
||||
static const char *mce_dump_aux_info(struct mce *m)
|
||||
{
|
||||
if (boot_cpu_has_bug(X86_BUG_TDX_PW_MCE))
|
||||
return tdx_dump_mce_info(m);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static noinstr void mce_panic(const char *msg, struct mce *final, char *exp)
|
||||
{
|
||||
struct llist_node *pending;
|
||||
struct mce_evt_llist *l;
|
||||
int apei_err = 0;
|
||||
struct page *p;
|
||||
const char *memmsg;
|
||||
|
||||
/*
|
||||
* Allow instrumentation around external facilities usage. Not that it
|
||||
@ -285,6 +294,11 @@ static noinstr void mce_panic(const char *msg, struct mce *final, char *exp)
|
||||
}
|
||||
if (exp)
|
||||
pr_emerg(HW_ERR "Machine check: %s\n", exp);
|
||||
|
||||
memmsg = mce_dump_aux_info(final);
|
||||
if (memmsg)
|
||||
pr_emerg(HW_ERR "Machine check: %s\n", memmsg);
|
||||
|
||||
if (!fake_panic) {
|
||||
if (panic_timeout == 0)
|
||||
panic_timeout = mca_cfg.panic_timeout;
|
||||
@ -297,6 +311,7 @@ static noinstr void mce_panic(const char *msg, struct mce *final, char *exp)
|
||||
*/
|
||||
if (kexec_crash_loaded()) {
|
||||
if (final && (final->status & MCI_STATUS_ADDRV)) {
|
||||
struct page *p;
|
||||
p = pfn_to_online_page(final->addr >> PAGE_SHIFT);
|
||||
if (p)
|
||||
SetPageHWPoison(p);
|
||||
|
@ -1031,6 +1031,8 @@ void __init setup_arch(char **cmdline_p)
|
||||
*
|
||||
* Moreover, on machines with SandyBridge graphics or in setups that use
|
||||
* crashkernel the entire 1M is reserved anyway.
|
||||
*
|
||||
* Note the host kernel TDX also requires the first 1MB being reserved.
|
||||
*/
|
||||
x86_platform.realmode_reserve();
|
||||
|
||||
|
@ -1,2 +1,2 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-y += seamcall.o
|
||||
obj-y += seamcall.o tdx.o
|
||||
|
1492
arch/x86/virt/vmx/tdx/tdx.c
Normal file
1492
arch/x86/virt/vmx/tdx/tdx.c
Normal file
File diff suppressed because it is too large
Load Diff
121
arch/x86/virt/vmx/tdx/tdx.h
Normal file
121
arch/x86/virt/vmx/tdx/tdx.h
Normal file
@ -0,0 +1,121 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _X86_VIRT_TDX_H
|
||||
#define _X86_VIRT_TDX_H
|
||||
|
||||
#include <linux/bits.h>
|
||||
|
||||
/*
|
||||
* This file contains both macros and data structures defined by the TDX
|
||||
* architecture and Linux defined software data structures and functions.
|
||||
* The two should not be mixed together for better readability. The
|
||||
* architectural definitions come first.
|
||||
*/
|
||||
|
||||
/*
|
||||
* TDX module SEAMCALL leaf functions
|
||||
*/
|
||||
#define TDH_PHYMEM_PAGE_RDMD 24
|
||||
#define TDH_SYS_KEY_CONFIG 31
|
||||
#define TDH_SYS_INIT 33
|
||||
#define TDH_SYS_RD 34
|
||||
#define TDH_SYS_LP_INIT 35
|
||||
#define TDH_SYS_TDMR_INIT 36
|
||||
#define TDH_SYS_CONFIG 45
|
||||
|
||||
/* TDX page types */
|
||||
#define PT_NDA 0x0
|
||||
#define PT_RSVD 0x1
|
||||
|
||||
/*
|
||||
* Global scope metadata field ID.
|
||||
*
|
||||
* See Table "Global Scope Metadata", TDX module 1.5 ABI spec.
|
||||
*/
|
||||
#define MD_FIELD_ID_MAX_TDMRS 0x9100000100000008ULL
|
||||
#define MD_FIELD_ID_MAX_RESERVED_PER_TDMR 0x9100000100000009ULL
|
||||
#define MD_FIELD_ID_PAMT_4K_ENTRY_SIZE 0x9100000100000010ULL
|
||||
#define MD_FIELD_ID_PAMT_2M_ENTRY_SIZE 0x9100000100000011ULL
|
||||
#define MD_FIELD_ID_PAMT_1G_ENTRY_SIZE 0x9100000100000012ULL
|
||||
|
||||
/*
|
||||
* Sub-field definition of metadata field ID.
|
||||
*
|
||||
* See Table "MD_FIELD_ID (Metadata Field Identifier / Sequence Header)
|
||||
* Definition", TDX module 1.5 ABI spec.
|
||||
*
|
||||
* - Bit 33:32: ELEMENT_SIZE_CODE -- size of a single element of metadata
|
||||
*
|
||||
* 0: 8 bits
|
||||
* 1: 16 bits
|
||||
* 2: 32 bits
|
||||
* 3: 64 bits
|
||||
*/
|
||||
#define MD_FIELD_ID_ELE_SIZE_CODE(_field_id) \
|
||||
(((_field_id) & GENMASK_ULL(33, 32)) >> 32)
|
||||
|
||||
#define MD_FIELD_ID_ELE_SIZE_16BIT 1
|
||||
|
||||
struct tdmr_reserved_area {
|
||||
u64 offset;
|
||||
u64 size;
|
||||
} __packed;
|
||||
|
||||
#define TDMR_INFO_ALIGNMENT 512
|
||||
#define TDMR_INFO_PA_ARRAY_ALIGNMENT 512
|
||||
|
||||
struct tdmr_info {
|
||||
u64 base;
|
||||
u64 size;
|
||||
u64 pamt_1g_base;
|
||||
u64 pamt_1g_size;
|
||||
u64 pamt_2m_base;
|
||||
u64 pamt_2m_size;
|
||||
u64 pamt_4k_base;
|
||||
u64 pamt_4k_size;
|
||||
/*
|
||||
* The actual number of reserved areas depends on the value of
|
||||
* field MD_FIELD_ID_MAX_RESERVED_PER_TDMR in the TDX module
|
||||
* global metadata.
|
||||
*/
|
||||
DECLARE_FLEX_ARRAY(struct tdmr_reserved_area, reserved_areas);
|
||||
} __packed __aligned(TDMR_INFO_ALIGNMENT);
|
||||
|
||||
/*
|
||||
* Do not put any hardware-defined TDX structure representations below
|
||||
* this comment!
|
||||
*/
|
||||
|
||||
/* Kernel defined TDX module status during module initialization. */
|
||||
enum tdx_module_status_t {
|
||||
TDX_MODULE_UNINITIALIZED,
|
||||
TDX_MODULE_INITIALIZED,
|
||||
TDX_MODULE_ERROR
|
||||
};
|
||||
|
||||
struct tdx_memblock {
|
||||
struct list_head list;
|
||||
unsigned long start_pfn;
|
||||
unsigned long end_pfn;
|
||||
int nid;
|
||||
};
|
||||
|
||||
/* "TDMR info" part of "Global Scope Metadata" for constructing TDMRs */
|
||||
struct tdx_tdmr_sysinfo {
|
||||
u16 max_tdmrs;
|
||||
u16 max_reserved_per_tdmr;
|
||||
u16 pamt_entry_size[TDX_PS_NR];
|
||||
};
|
||||
|
||||
/* Warn if kernel has less than TDMR_NR_WARN TDMRs after allocation */
|
||||
#define TDMR_NR_WARN 4
|
||||
|
||||
struct tdmr_info_list {
|
||||
void *tdmrs; /* Flexible array to hold 'tdmr_info's */
|
||||
int nr_consumed_tdmrs; /* How many 'tdmr_info's are in use */
|
||||
|
||||
/* Metadata for finding target 'tdmr_info' and freeing @tdmrs */
|
||||
int tdmr_sz; /* Size of one 'tdmr_info' */
|
||||
int max_tdmrs; /* How many 'tdmr_info's are allocated */
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user