diff mbox series

[v19,046/130] KVM: x86/mmu: Add address conversion functions for TDX shared bit of GPA

Message ID 973a3e06111fe84f2b1e971636cbaa3facf7b120.1708933498.git.isaku.yamahata@intel.com (mailing list archive)
State New, archived
Headers show
Series [v19,001/130] x86/virt/tdx: Rename _offset to _member for TD_SYSINFO_MAP() macro | expand

Commit Message

Isaku Yamahata Feb. 26, 2024, 8:25 a.m. UTC
From: Isaku Yamahata <isaku.yamahata@intel.com>

TDX repurposes one GPA bit (51 bit or 47 bit based on configuration) to
indicate the GPA is private(if cleared) or shared (if set) with VMM.  If
GPA.shared is set, GPA is covered by the existing conventional EPT pointed
by EPTP.  If GPA.shared bit is cleared, GPA is covered by TDX module.
VMM has to issue SEAMCALLs to operate.

Add a member to remember GPA shared bit for each guest TDs, add address
conversion functions between private GPA and shared GPA and test if GPA
is private.

Because struct kvm_arch (or struct kvm which includes struct kvm_arch. See
kvm_arch_alloc_vm() that passes __GPF_ZERO) is zero-cleared when allocated,
the new member to remember GPA shared bit is guaranteed to be zero with
this patch unless it's initialized explicitly.

			default or SEV-SNP	TDX: S = (47 or 51) - 12
gfn_shared_mask		0			S bit
kvm_is_private_gpa()	always false		true if GFN has S bit set
kvm_gfn_to_shared()	nop			set S bit
kvm_gfn_to_private()	nop			clear S bit

fault.is_private means that host page should be gotten from guest_memfd
is_private_gpa() means that KVM MMU should invoke private MMU hooks.

Co-developed-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
---
v19:
- Add comment on default vm case.
- Added behavior table in the commit message
- drop CONFIG_KVM_MMU_PRIVATE

v18:
- Added Reviewed-by Binbin

Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
---
 arch/x86/include/asm/kvm_host.h |  2 ++
 arch/x86/kvm/mmu.h              | 33 +++++++++++++++++++++++++++++++++
 arch/x86/kvm/vmx/tdx.c          |  5 +++++
 3 files changed, 40 insertions(+)

Comments

Chenyi Qiang March 27, 2024, 3:08 a.m. UTC | #1
On 2/26/2024 4:25 PM, isaku.yamahata@intel.com wrote:
> From: Isaku Yamahata <isaku.yamahata@intel.com>
> 
> TDX repurposes one GPA bit (51 bit or 47 bit based on configuration) to
> indicate the GPA is private(if cleared) or shared (if set) with VMM.  If
> GPA.shared is set, GPA is covered by the existing conventional EPT pointed
> by EPTP.  If GPA.shared bit is cleared, GPA is covered by TDX module.
> VMM has to issue SEAMCALLs to operate.
> 
> Add a member to remember GPA shared bit for each guest TDs, add address
> conversion functions between private GPA and shared GPA and test if GPA
> is private.
> 
> Because struct kvm_arch (or struct kvm which includes struct kvm_arch. See
> kvm_arch_alloc_vm() that passes __GPF_ZERO) is zero-cleared when allocated,
> the new member to remember GPA shared bit is guaranteed to be zero with
> this patch unless it's initialized explicitly.
> 
> 			default or SEV-SNP	TDX: S = (47 or 51) - 12
> gfn_shared_mask		0			S bit
> kvm_is_private_gpa()	always false		true if GFN has S bit set

TDX: true if GFN has S bit clear?

> kvm_gfn_to_shared()	nop			set S bit
> kvm_gfn_to_private()	nop			clear S bit
> 
> fault.is_private means that host page should be gotten from guest_memfd
> is_private_gpa() means that KVM MMU should invoke private MMU hooks.
> 
> Co-developed-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
> Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
> Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
> Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
> ---
> v19:
> - Add comment on default vm case.
> - Added behavior table in the commit message
> - drop CONFIG_KVM_MMU_PRIVATE
> 
> v18:
> - Added Reviewed-by Binbin
> 
> Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
> ---
>  arch/x86/include/asm/kvm_host.h |  2 ++
>  arch/x86/kvm/mmu.h              | 33 +++++++++++++++++++++++++++++++++
>  arch/x86/kvm/vmx/tdx.c          |  5 +++++
>  3 files changed, 40 insertions(+)
> 
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index 5da3c211955d..de6dd42d226f 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -1505,6 +1505,8 @@ struct kvm_arch {
>  	 */
>  #define SPLIT_DESC_CACHE_MIN_NR_OBJECTS (SPTE_ENT_PER_PAGE + 1)
>  	struct kvm_mmu_memory_cache split_desc_cache;
> +
> +	gfn_t gfn_shared_mask;
>  };
>  
>  struct kvm_vm_stat {
> diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
> index d96c93a25b3b..395b55684cb9 100644
> --- a/arch/x86/kvm/mmu.h
> +++ b/arch/x86/kvm/mmu.h
> @@ -322,4 +322,37 @@ static inline gpa_t kvm_translate_gpa(struct kvm_vcpu *vcpu,
>  		return gpa;
>  	return translate_nested_gpa(vcpu, gpa, access, exception);
>  }
> +
> +/*
> + *			default or SEV-SNP	TDX: where S = (47 or 51) - 12
> + * gfn_shared_mask	0			S bit
> + * is_private_gpa()	always false		if GPA has S bit set
> + * gfn_to_shared()	nop			set S bit
> + * gfn_to_private()	nop			clear S bit
> + *
> + * fault.is_private means that host page should be gotten from guest_memfd
> + * is_private_gpa() means that KVM MMU should invoke private MMU hooks.
> + */
> +static inline gfn_t kvm_gfn_shared_mask(const struct kvm *kvm)
> +{
> +	return kvm->arch.gfn_shared_mask;
> +}
> +
> +static inline gfn_t kvm_gfn_to_shared(const struct kvm *kvm, gfn_t gfn)
> +{
> +	return gfn | kvm_gfn_shared_mask(kvm);
> +}
> +
> +static inline gfn_t kvm_gfn_to_private(const struct kvm *kvm, gfn_t gfn)
> +{
> +	return gfn & ~kvm_gfn_shared_mask(kvm);
> +}
> +
> +static inline bool kvm_is_private_gpa(const struct kvm *kvm, gpa_t gpa)
> +{
> +	gfn_t mask = kvm_gfn_shared_mask(kvm);
> +
> +	return mask && !(gpa_to_gfn(gpa) & mask);
> +}
> +
>  #endif
> diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
> index aa1da51b8af7..54e0d4efa2bd 100644
> --- a/arch/x86/kvm/vmx/tdx.c
> +++ b/arch/x86/kvm/vmx/tdx.c
> @@ -906,6 +906,11 @@ static int tdx_td_init(struct kvm *kvm, struct kvm_tdx_cmd *cmd)
>  	kvm_tdx->attributes = td_params->attributes;
>  	kvm_tdx->xfam = td_params->xfam;
>  
> +	if (td_params->exec_controls & TDX_EXEC_CONTROL_MAX_GPAW)
> +		kvm->arch.gfn_shared_mask = gpa_to_gfn(BIT_ULL(51));
> +	else
> +		kvm->arch.gfn_shared_mask = gpa_to_gfn(BIT_ULL(47));
> +
>  out:
>  	/* kfree() accepts NULL. */
>  	kfree(init_vm);
Binbin Wu March 27, 2024, 2:09 p.m. UTC | #2
On 3/27/2024 11:08 AM, Chenyi Qiang wrote:
>
> On 2/26/2024 4:25 PM, isaku.yamahata@intel.com wrote:
>> From: Isaku Yamahata <isaku.yamahata@intel.com>
>>
>> TDX repurposes one GPA bit (51 bit or 47 bit based on configuration) to
>> indicate the GPA is private(if cleared) or shared (if set) with VMM.  If
>> GPA.shared is set, GPA is covered by the existing conventional EPT pointed
>> by EPTP.  If GPA.shared bit is cleared, GPA is covered by TDX module.
>> VMM has to issue SEAMCALLs to operate.
>>
>> Add a member to remember GPA shared bit for each guest TDs, add address
>> conversion functions between private GPA and shared GPA and test if GPA
>> is private.
>>
>> Because struct kvm_arch (or struct kvm which includes struct kvm_arch. See
>> kvm_arch_alloc_vm() that passes __GPF_ZERO) is zero-cleared when allocated,
>> the new member to remember GPA shared bit is guaranteed to be zero with
>> this patch unless it's initialized explicitly.
>>
>> 			default or SEV-SNP	TDX: S = (47 or 51) - 12
>> gfn_shared_mask		0			S bit
>> kvm_is_private_gpa()	always false		true if GFN has S bit set
> TDX: true if GFN has S bit clear?
>
>> kvm_gfn_to_shared()	nop			set S bit
>> kvm_gfn_to_private()	nop			clear S bit
>>
>> fault.is_private means that host page should be gotten from guest_memfd
>> is_private_gpa() means that KVM MMU should invoke private MMU hooks.
>>
>> Co-developed-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
>> Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
>> Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
>> Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
>> ---
>> v19:
>> - Add comment on default vm case.
>> - Added behavior table in the commit message
>> - drop CONFIG_KVM_MMU_PRIVATE
>>
>> v18:
>> - Added Reviewed-by Binbin
>>
>> Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
>> ---
>>   arch/x86/include/asm/kvm_host.h |  2 ++
>>   arch/x86/kvm/mmu.h              | 33 +++++++++++++++++++++++++++++++++
>>   arch/x86/kvm/vmx/tdx.c          |  5 +++++
>>   3 files changed, 40 insertions(+)
>>
>> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
>> index 5da3c211955d..de6dd42d226f 100644
>> --- a/arch/x86/include/asm/kvm_host.h
>> +++ b/arch/x86/include/asm/kvm_host.h
>> @@ -1505,6 +1505,8 @@ struct kvm_arch {
>>   	 */
>>   #define SPLIT_DESC_CACHE_MIN_NR_OBJECTS (SPTE_ENT_PER_PAGE + 1)
>>   	struct kvm_mmu_memory_cache split_desc_cache;
>> +
>> +	gfn_t gfn_shared_mask;
>>   };
>>   
>>   struct kvm_vm_stat {
>> diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
>> index d96c93a25b3b..395b55684cb9 100644
>> --- a/arch/x86/kvm/mmu.h
>> +++ b/arch/x86/kvm/mmu.h
>> @@ -322,4 +322,37 @@ static inline gpa_t kvm_translate_gpa(struct kvm_vcpu *vcpu,
>>   		return gpa;
>>   	return translate_nested_gpa(vcpu, gpa, access, exception);
>>   }
>> +
>> +/*
>> + *			default or SEV-SNP	TDX: where S = (47 or 51) - 12
>> + * gfn_shared_mask	0			S bit
>> + * is_private_gpa()	always false		if GPA has S bit set

Also here,
TDX: true if GFN has S bit cleared

>> + * gfn_to_shared()	nop			set S bit
>> + * gfn_to_private()	nop			clear S bit
>> + *
>> + * fault.is_private means that host page should be gotten from guest_memfd
>> + * is_private_gpa() means that KVM MMU should invoke private MMU hooks.
>> + */
>> +static inline gfn_t kvm_gfn_shared_mask(const struct kvm *kvm)
>> +{
>> +	return kvm->arch.gfn_shared_mask;
>> +}
>> +
>> +static inline gfn_t kvm_gfn_to_shared(const struct kvm *kvm, gfn_t gfn)
>> +{
>> +	return gfn | kvm_gfn_shared_mask(kvm);
>> +}
>> +
>> +static inline gfn_t kvm_gfn_to_private(const struct kvm *kvm, gfn_t gfn)
>> +{
>> +	return gfn & ~kvm_gfn_shared_mask(kvm);
>> +}
>> +
>> +static inline bool kvm_is_private_gpa(const struct kvm *kvm, gpa_t gpa)
>> +{
>> +	gfn_t mask = kvm_gfn_shared_mask(kvm);
>> +
>> +	return mask && !(gpa_to_gfn(gpa) & mask);
>> +}
>> +
>>   #endif
>> diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
>> index aa1da51b8af7..54e0d4efa2bd 100644
>> --- a/arch/x86/kvm/vmx/tdx.c
>> +++ b/arch/x86/kvm/vmx/tdx.c
>> @@ -906,6 +906,11 @@ static int tdx_td_init(struct kvm *kvm, struct kvm_tdx_cmd *cmd)
>>   	kvm_tdx->attributes = td_params->attributes;
>>   	kvm_tdx->xfam = td_params->xfam;
>>   
>> +	if (td_params->exec_controls & TDX_EXEC_CONTROL_MAX_GPAW)
>> +		kvm->arch.gfn_shared_mask = gpa_to_gfn(BIT_ULL(51));
>> +	else
>> +		kvm->arch.gfn_shared_mask = gpa_to_gfn(BIT_ULL(47));
>> +
>>   out:
>>   	/* kfree() accepts NULL. */
>>   	kfree(init_vm);
Isaku Yamahata March 27, 2024, 11:50 p.m. UTC | #3
On Wed, Mar 27, 2024 at 10:09:21PM +0800,
Binbin Wu <binbin.wu@linux.intel.com> wrote:

> 
> 
> On 3/27/2024 11:08 AM, Chenyi Qiang wrote:
> > 
> > On 2/26/2024 4:25 PM, isaku.yamahata@intel.com wrote:
> > > From: Isaku Yamahata <isaku.yamahata@intel.com>
> > > 
> > > TDX repurposes one GPA bit (51 bit or 47 bit based on configuration) to
> > > indicate the GPA is private(if cleared) or shared (if set) with VMM.  If
> > > GPA.shared is set, GPA is covered by the existing conventional EPT pointed
> > > by EPTP.  If GPA.shared bit is cleared, GPA is covered by TDX module.
> > > VMM has to issue SEAMCALLs to operate.
> > > 
> > > Add a member to remember GPA shared bit for each guest TDs, add address
> > > conversion functions between private GPA and shared GPA and test if GPA
> > > is private.
> > > 
> > > Because struct kvm_arch (or struct kvm which includes struct kvm_arch. See
> > > kvm_arch_alloc_vm() that passes __GPF_ZERO) is zero-cleared when allocated,
> > > the new member to remember GPA shared bit is guaranteed to be zero with
> > > this patch unless it's initialized explicitly.
> > > 
> > > 			default or SEV-SNP	TDX: S = (47 or 51) - 12
> > > gfn_shared_mask		0			S bit
> > > kvm_is_private_gpa()	always false		true if GFN has S bit set
> > TDX: true if GFN has S bit clear?
> > 
> > > kvm_gfn_to_shared()	nop			set S bit
> > > kvm_gfn_to_private()	nop			clear S bit
> > > 
> > > fault.is_private means that host page should be gotten from guest_memfd
> > > is_private_gpa() means that KVM MMU should invoke private MMU hooks.
> > > 
> > > Co-developed-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
> > > Signed-off-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
> > > Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
> > > Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
> > > ---
> > > v19:
> > > - Add comment on default vm case.
> > > - Added behavior table in the commit message
> > > - drop CONFIG_KVM_MMU_PRIVATE
> > > 
> > > v18:
> > > - Added Reviewed-by Binbin
> > > 
> > > Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com>
> > > ---
> > >   arch/x86/include/asm/kvm_host.h |  2 ++
> > >   arch/x86/kvm/mmu.h              | 33 +++++++++++++++++++++++++++++++++
> > >   arch/x86/kvm/vmx/tdx.c          |  5 +++++
> > >   3 files changed, 40 insertions(+)
> > > 
> > > diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> > > index 5da3c211955d..de6dd42d226f 100644
> > > --- a/arch/x86/include/asm/kvm_host.h
> > > +++ b/arch/x86/include/asm/kvm_host.h
> > > @@ -1505,6 +1505,8 @@ struct kvm_arch {
> > >   	 */
> > >   #define SPLIT_DESC_CACHE_MIN_NR_OBJECTS (SPTE_ENT_PER_PAGE + 1)
> > >   	struct kvm_mmu_memory_cache split_desc_cache;
> > > +
> > > +	gfn_t gfn_shared_mask;
> > >   };
> > >   struct kvm_vm_stat {
> > > diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
> > > index d96c93a25b3b..395b55684cb9 100644
> > > --- a/arch/x86/kvm/mmu.h
> > > +++ b/arch/x86/kvm/mmu.h
> > > @@ -322,4 +322,37 @@ static inline gpa_t kvm_translate_gpa(struct kvm_vcpu *vcpu,
> > >   		return gpa;
> > >   	return translate_nested_gpa(vcpu, gpa, access, exception);
> > >   }
> > > +
> > > +/*
> > > + *			default or SEV-SNP	TDX: where S = (47 or 51) - 12
> > > + * gfn_shared_mask	0			S bit
> > > + * is_private_gpa()	always false		if GPA has S bit set
> 
> Also here,
> TDX: true if GFN has S bit cleared

Oops. Will fix both.
diff mbox series

Patch

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 5da3c211955d..de6dd42d226f 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1505,6 +1505,8 @@  struct kvm_arch {
 	 */
 #define SPLIT_DESC_CACHE_MIN_NR_OBJECTS (SPTE_ENT_PER_PAGE + 1)
 	struct kvm_mmu_memory_cache split_desc_cache;
+
+	gfn_t gfn_shared_mask;
 };
 
 struct kvm_vm_stat {
diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
index d96c93a25b3b..395b55684cb9 100644
--- a/arch/x86/kvm/mmu.h
+++ b/arch/x86/kvm/mmu.h
@@ -322,4 +322,37 @@  static inline gpa_t kvm_translate_gpa(struct kvm_vcpu *vcpu,
 		return gpa;
 	return translate_nested_gpa(vcpu, gpa, access, exception);
 }
+
+/*
+ *			default or SEV-SNP	TDX: where S = (47 or 51) - 12
+ * gfn_shared_mask	0			S bit
+ * is_private_gpa()	always false		if GPA has S bit set
+ * gfn_to_shared()	nop			set S bit
+ * gfn_to_private()	nop			clear S bit
+ *
+ * fault.is_private means that host page should be gotten from guest_memfd
+ * is_private_gpa() means that KVM MMU should invoke private MMU hooks.
+ */
+static inline gfn_t kvm_gfn_shared_mask(const struct kvm *kvm)
+{
+	return kvm->arch.gfn_shared_mask;
+}
+
+static inline gfn_t kvm_gfn_to_shared(const struct kvm *kvm, gfn_t gfn)
+{
+	return gfn | kvm_gfn_shared_mask(kvm);
+}
+
+static inline gfn_t kvm_gfn_to_private(const struct kvm *kvm, gfn_t gfn)
+{
+	return gfn & ~kvm_gfn_shared_mask(kvm);
+}
+
+static inline bool kvm_is_private_gpa(const struct kvm *kvm, gpa_t gpa)
+{
+	gfn_t mask = kvm_gfn_shared_mask(kvm);
+
+	return mask && !(gpa_to_gfn(gpa) & mask);
+}
+
 #endif
diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index aa1da51b8af7..54e0d4efa2bd 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -906,6 +906,11 @@  static int tdx_td_init(struct kvm *kvm, struct kvm_tdx_cmd *cmd)
 	kvm_tdx->attributes = td_params->attributes;
 	kvm_tdx->xfam = td_params->xfam;
 
+	if (td_params->exec_controls & TDX_EXEC_CONTROL_MAX_GPAW)
+		kvm->arch.gfn_shared_mask = gpa_to_gfn(BIT_ULL(51));
+	else
+		kvm->arch.gfn_shared_mask = gpa_to_gfn(BIT_ULL(47));
+
 out:
 	/* kfree() accepts NULL. */
 	kfree(init_vm);