2024-03-09 21:03:09

by Kirill A. Shutemov

[permalink] [raw]
Subject: [PATCH 0/4] Adjust TD settings on boot

Adjust TD setting on boot:

- Disable EPT violation #VE on private memory if TD can
control it;

- Enable virtualization of topology-related CPUID leafs
X2APIC_APICID MSR;

Kirill A. Shutemov (4):
x86/tdx: Introduce tdg_vm_wr()
x86/tdx: Rename tdx_parse_tdinfo() to tdx_setup()
x86/tdx: Handle PENDING_EPT_VIOLATION_V2
x86/tdx: Enable ENUM_TOPOLOGY

arch/x86/coco/tdx/tdx.c | 117 ++++++++++++++++++++++++++----
arch/x86/include/asm/shared/tdx.h | 21 +++++-
2 files changed, 123 insertions(+), 15 deletions(-)

--
2.43.0



2024-03-09 21:03:34

by Kirill A. Shutemov

[permalink] [raw]
Subject: [PATCH 2/4] x86/tdx: Rename tdx_parse_tdinfo() to tdx_setup()

Rename tdx_parse_tdinfo() to tdx_setup() and move setting NOTIFY_ENABLES
there.

The function will be extended to adjust TD configuration.

Signed-off-by: Kirill A. Shutemov <[email protected]>
---
arch/x86/coco/tdx/tdx.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c
index 5ffe5ef99536..afdaf46cabb9 100644
--- a/arch/x86/coco/tdx/tdx.c
+++ b/arch/x86/coco/tdx/tdx.c
@@ -181,7 +181,7 @@ static void __noreturn tdx_panic(const char *msg)
__tdx_hypercall(&args);
}

-static void tdx_parse_tdinfo(u64 *cc_mask)
+static void tdx_setup(u64 *cc_mask)
{
struct tdx_module_args args = {};
unsigned int gpa_width;
@@ -206,6 +206,9 @@ static void tdx_parse_tdinfo(u64 *cc_mask)
gpa_width = args.rcx & GENMASK(5, 0);
*cc_mask = BIT_ULL(gpa_width - 1);

+ /* Kernel does not use NOTIFY_ENABLES and does not need random #VEs */
+ tdg_vm_wr(TDCS_NOTIFY_ENABLES, 0, -1ULL);
+
/*
* The kernel can not handle #VE's when accessing normal kernel
* memory. Ensure that no #VE will be delivered for accesses to
@@ -930,11 +933,11 @@ void __init tdx_early_init(void)
setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);

cc_vendor = CC_VENDOR_INTEL;
- tdx_parse_tdinfo(&cc_mask);
- cc_set_mask(cc_mask);

- /* Kernel does not use NOTIFY_ENABLES and does not need random #VEs */
- tdg_vm_wr(TDCS_NOTIFY_ENABLES, 0, -1ULL);
+ /* Configure the TD */
+ tdx_setup(&cc_mask);
+
+ cc_set_mask(cc_mask);

/*
* All bits above GPA width are reserved and kernel treats shared bit
--
2.43.0


2024-03-09 23:00:10

by Kirill A. Shutemov

[permalink] [raw]
Subject: [PATCH 3/4] x86/tdx: Handle PENDING_EPT_VIOLATION_V2

PENDING_EPT_VIOLATION_V2 allows TD to control whether access to
a pending page triggers #VE.

Kernel doesn't want to see any #VEs on accesses to private memory:
disable such #VEs.

Signed-off-by: Kirill A. Shutemov <[email protected]>
---
arch/x86/coco/tdx/tdx.c | 66 ++++++++++++++++++++++++++++---
arch/x86/include/asm/shared/tdx.h | 18 ++++++++-
2 files changed, 78 insertions(+), 6 deletions(-)

diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c
index afdaf46cabb9..d9ea82f8772d 100644
--- a/arch/x86/coco/tdx/tdx.c
+++ b/arch/x86/coco/tdx/tdx.c
@@ -77,6 +77,17 @@ static inline void tdcall(u64 fn, struct tdx_module_args *args)
panic("TDCALL %lld failed (Buggy TDX module!)\n", fn);
}

+static inline u64 tdg_vm_rd(u64 field)
+{
+ struct tdx_module_args args = {
+ .rdx = field,
+ };
+
+ tdcall(TDG_VM_RD, &args);
+
+ return args.r8;
+}
+
static inline u64 tdg_vm_wr(u64 field, u64 value, u64 mask)
{
struct tdx_module_args args = {
@@ -91,6 +102,17 @@ static inline u64 tdg_vm_wr(u64 field, u64 value, u64 mask)
return args.r8;
}

+static inline u64 tdg_sys_rd(u64 field)
+{
+ struct tdx_module_args args = {
+ .rdx = field,
+ };
+
+ tdcall(TDG_SYS_RD, &args);
+
+ return args.r8;
+}
+
/**
* tdx_mcall_get_report0() - Wrapper to get TDREPORT0 (a.k.a. TDREPORT
* subtype 0) using TDG.MR.REPORT TDCALL.
@@ -185,7 +207,8 @@ static void tdx_setup(u64 *cc_mask)
{
struct tdx_module_args args = {};
unsigned int gpa_width;
- u64 td_attr;
+ u64 td_attr, features;
+ bool sept_ve_disabled;

/*
* TDINFO TDX module call is used to get the TD execution environment
@@ -206,19 +229,52 @@ static void tdx_setup(u64 *cc_mask)
gpa_width = args.rcx & GENMASK(5, 0);
*cc_mask = BIT_ULL(gpa_width - 1);

+ td_attr = args.rdx;
+
/* Kernel does not use NOTIFY_ENABLES and does not need random #VEs */
tdg_vm_wr(TDCS_NOTIFY_ENABLES, 0, -1ULL);

+ features = tdg_sys_rd(TDCS_TDX_FEATURES0);
+
/*
* The kernel can not handle #VE's when accessing normal kernel
* memory. Ensure that no #VE will be delivered for accesses to
* TD-private memory. Only VMM-shared memory (MMIO) will #VE.
+ *
+ * Check if the TD is created with SEPT #VE disabled.
*/
- td_attr = args.rdx;
- if (!(td_attr & ATTR_SEPT_VE_DISABLE)) {
- const char *msg = "TD misconfiguration: SEPT_VE_DISABLE attribute must be set.";
+ sept_ve_disabled = td_attr & ATTR_SEPT_VE_DISABLE;

- /* Relax SEPT_VE_DISABLE check for debug TD. */
+ /*
+ * Check if flexible control of SEPT #VE is supported.
+ *
+ * The check consists of verifying if the feature is supported by the
+ * TDX module (the TDX_FEATURES0 check) and if the feature is enabled
+ * for this TD (CONFIG_FLAGS check).
+ *
+ * If flexible control is supported, disable SEPT #VE.
+ *
+ * Disable SEPT #VE regardless of ATTR_SEPT_VE_DISABLE status as
+ * flexible control allows software running before the kernel to
+ * enable it.
+ *
+ * Skip SEPT disabling for debug TD. SEPT #VE is unsafe but can be
+ * useful for debugging to produce a stack trace. Known to be useful
+ * for debugging unaccepted memory problems.
+ */
+ if (features & TDX_FEATURES0_PENDING_EPT_VIOLATION_V2 &&
+ (tdg_vm_rd(TDCS_CONFIG_FLAGS) & TDCS_CONFIG_FLEXIBLE_PENDING_VE) &&
+ !(td_attr & ATTR_DEBUG)) {
+ tdg_vm_wr(TDCS_TD_CTLS,
+ TD_CTLS_PENDING_VE_DISABLE,
+ TD_CTLS_PENDING_VE_DISABLE);
+ sept_ve_disabled = true;
+ }
+
+ if (!sept_ve_disabled) {
+ const char *msg = "TD misconfiguration: SEPT #VE has to be disabled";
+
+ /* Relax SEPT #VE disable check for debug TD. */
if (td_attr & ATTR_DEBUG)
pr_warn("%s\n", msg);
else
diff --git a/arch/x86/include/asm/shared/tdx.h b/arch/x86/include/asm/shared/tdx.h
index fdfd41511b02..29a61c72e4dd 100644
--- a/arch/x86/include/asm/shared/tdx.h
+++ b/arch/x86/include/asm/shared/tdx.h
@@ -16,11 +16,27 @@
#define TDG_VP_VEINFO_GET 3
#define TDG_MR_REPORT 4
#define TDG_MEM_PAGE_ACCEPT 6
+#define TDG_VM_RD 7
#define TDG_VM_WR 8
+#define TDG_SYS_RD 11

-/* TDCS fields. To be used by TDG.VM.WR and TDG.VM.RD module calls */
+/* TDX Global Metadata. To be used by TDG.SYS.RD */
+#define TDCS_TDX_FEATURES0 0x0A00000300000008
+
+/* TDX TD-Scope Metadata. To be used by TDG.VM.WR and TDG.VM.RD */
+#define TDCS_CONFIG_FLAGS 0x1110000300000016
+#define TDCS_TD_CTLS 0x1110000300000017
#define TDCS_NOTIFY_ENABLES 0x9100000000000010

+/* TDCS_TDX_FEATURES0 bits */
+#define TDX_FEATURES0_PENDING_EPT_VIOLATION_V2 BIT_ULL(16)
+
+/* TDCS_CONFIG_FLAGS bits */
+#define TDCS_CONFIG_FLEXIBLE_PENDING_VE BIT_ULL(1)
+
+/* TDCS_TD_CTLS bits */
+#define TD_CTLS_PENDING_VE_DISABLE BIT_ULL(0)
+
/* TDX hypercall Leaf IDs */
#define TDVMCALL_MAP_GPA 0x10001
#define TDVMCALL_GET_QUOTE 0x10002
--
2.43.0


Subject: Re: [PATCH 2/4] x86/tdx: Rename tdx_parse_tdinfo() to tdx_setup()


On 3/9/24 1:02 PM, Kirill A. Shutemov wrote:
> Rename tdx_parse_tdinfo() to tdx_setup() and move setting NOTIFY_ENABLES
> there.
>
> The function will be extended to adjust TD configuration.
>
> Signed-off-by: Kirill A. Shutemov <[email protected]>
> ---

Looks good to me.

Reviewed-by: Kuppuswamy Sathyanarayanan <[email protected]>

> arch/x86/coco/tdx/tdx.c | 13 ++++++++-----
> 1 file changed, 8 insertions(+), 5 deletions(-)
>
> diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c
> index 5ffe5ef99536..afdaf46cabb9 100644
> --- a/arch/x86/coco/tdx/tdx.c
> +++ b/arch/x86/coco/tdx/tdx.c
> @@ -181,7 +181,7 @@ static void __noreturn tdx_panic(const char *msg)
> __tdx_hypercall(&args);
> }
>
> -static void tdx_parse_tdinfo(u64 *cc_mask)
> +static void tdx_setup(u64 *cc_mask)
> {
> struct tdx_module_args args = {};
> unsigned int gpa_width;
> @@ -206,6 +206,9 @@ static void tdx_parse_tdinfo(u64 *cc_mask)
> gpa_width = args.rcx & GENMASK(5, 0);
> *cc_mask = BIT_ULL(gpa_width - 1);
>
> + /* Kernel does not use NOTIFY_ENABLES and does not need random #VEs */
> + tdg_vm_wr(TDCS_NOTIFY_ENABLES, 0, -1ULL);
> +
> /*
> * The kernel can not handle #VE's when accessing normal kernel
> * memory. Ensure that no #VE will be delivered for accesses to
> @@ -930,11 +933,11 @@ void __init tdx_early_init(void)
> setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
>
> cc_vendor = CC_VENDOR_INTEL;
> - tdx_parse_tdinfo(&cc_mask);
> - cc_set_mask(cc_mask);
>
> - /* Kernel does not use NOTIFY_ENABLES and does not need random #VEs */
> - tdg_vm_wr(TDCS_NOTIFY_ENABLES, 0, -1ULL);
> + /* Configure the TD */
> + tdx_setup(&cc_mask);
> +
> + cc_set_mask(cc_mask);
>
> /*
> * All bits above GPA width are reserved and kernel treats shared bit

--
Sathyanarayanan Kuppuswamy
Linux Kernel Developer