Re: [PATCH 22/25] KVM: TDX: Use guest physical address to configure EPT level and GPAW

From: Xiaoyao Li
Date: Thu Oct 10 2024 - 05:18:17 EST


On 8/13/2024 6:48 AM, Rick Edgecombe wrote:
From: Xiaoyao Li <xiaoyao.li@xxxxxxxxx>

KVM reports guest physical address in CPUID.0x800000008.EAX[23:16],
which is similar to TDX's GPAW. Use this field as the interface for
userspace to configure the GPAW and EPT level for TDs.

Note,

1. only value 48 and 52 are supported. 52 means GPAW-52 and EPT level
5, and 48 means GPAW-48 and EPT level 4.
2. value 48, i.e., GPAW-48 is always supported. value 52 is only
supported when the platform supports 5 level EPT.

Current TDX module doesn't support max_gpa configuration. However
current implementation relies on max_gpa to configure EPT level and
GPAW. Hack KVM to make it work.

This patch needs to be squashed into patch 14.

Signed-off-by: Xiaoyao Li <xiaoyao.li@xxxxxxxxx>
Signed-off-by: Rick Edgecombe <rick.p.edgecombe@xxxxxxxxx>
---
uAPI breakout v1:
- New patch
---
arch/x86/kvm/vmx/tdx.c | 32 +++++++++++++++++++-------------
1 file changed, 19 insertions(+), 13 deletions(-)

diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index fe2bbc2ced41..c6bfeb0b3cc9 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -514,23 +514,22 @@ static int setup_tdparams_eptp_controls(struct kvm_cpuid2 *cpuid,
struct td_params *td_params)
{
const struct kvm_cpuid_entry2 *entry;
- int max_pa = 36;
+ int guest_pa;
entry = kvm_find_cpuid_entry2(cpuid->entries, cpuid->nent, 0x80000008, 0);
- if (entry)
- max_pa = entry->eax & 0xff;
+ if (!entry)
+ return -EINVAL;
+
+ guest_pa = (entry->eax >> 16) & 0xff;
+
+ if (guest_pa != 48 && guest_pa != 52)
+ return -EINVAL;
+
+ if (guest_pa == 52 && !cpu_has_vmx_ept_5levels())
+ return -EINVAL;
td_params->eptp_controls = VMX_EPTP_MT_WB;
- /*
- * No CPU supports 4-level && max_pa > 48.
- * "5-level paging and 5-level EPT" section 4.1 4-level EPT
- * "4-level EPT is limited to translating 48-bit guest-physical
- * addresses."
- * cpu_has_vmx_ept_5levels() check is just in case.
- */
- if (!cpu_has_vmx_ept_5levels() && max_pa > 48)
- return -EINVAL;
- if (cpu_has_vmx_ept_5levels() && max_pa > 48) {
+ if (guest_pa == 52) {
td_params->eptp_controls |= VMX_EPTP_PWL_5;
td_params->exec_controls |= TDX_EXEC_CONTROL_MAX_GPAW;
} else {
@@ -576,6 +575,9 @@ static int setup_tdparams_cpuids(struct kvm_cpuid2 *cpuid,
value->ebx = entry->ebx;
value->ecx = entry->ecx;
value->edx = entry->edx;
+
+ if (c->leaf == 0x80000008)
+ value->eax &= 0xff00ffff;
}
return 0;
@@ -1277,6 +1279,10 @@ static int __init setup_kvm_tdx_caps(void)
memcpy(dest, &source, sizeof(struct kvm_tdx_cpuid_config));
if (dest->sub_leaf == KVM_TDX_CPUID_NO_SUBLEAF)
dest->sub_leaf = 0;
+
+ /* Work around missing support on old TDX modules */
+ if (dest->leaf == 0x80000008)
+ dest->eax |= 0x00ff0000;
}
return 0;