diff mbox series

x86/sgx: Allow exposing EDECCSSA user leaf function to KVM guest

Message ID 20220727115442.464380-1-kai.huang@intel.com (mailing list archive)
State New, archived
Headers show
Series x86/sgx: Allow exposing EDECCSSA user leaf function to KVM guest | expand

Commit Message

Huang, Kai July 27, 2022, 11:54 a.m. UTC
Coupled with the new SGX attribute to allow one enclave to receive the
AEX notification, SGX also adds a new EDECCSSA user leaf function to
facilitate the AEX notification handling.  The new EDECCSSA is
enumerated via CPUID(EAX=0x12,ECX=0x0):EAX[11].

Besides Allowing reporting the new AEX-notify attribute to KVM guests,
also allow reporting the new EDECCSSA user leaf function to KVM guests
so the guest can fully utilize the AEX-notify mechanism.

Introduce a new X86 CPU feature flag for the new EDECCSSA, and report it
in KVM's supported CPUIDs so the userspace hypervisor (i.e. Qemu) can
enable it for the guest.

Note there's no additional enabling work required to allow guest to use
the new EDECCSSA.  KVM is not able to trap ENCLU anyway.

More background about how do AEX-notify and EDECCSSA work:

The new Asynchronous Exit (AEX) notification mechanism (AEX-notify)
allows one enclave to receive a notification in the ERESUME after the
enclave exit due to an AEX.  EDECCSSA is a new SGX user leaf function
(ENCLU[EDECCSSA]) to facilitate the AEX notification handling.

SGX maintains a Current State Save Area Frame (CSSA) for each enclave
thread.  When AEX happens, the enclave thread context is saved to the
CSSA and the CSSA is increased by 1.  For a normal ERESUME which doesn't
deliver AEX notification, it restores the saved thread context from the
previously saved SSA and decreases the CSSA.  If AEX-notify is enabled
for one enclave, the ERESUME acts differently.  Instead of restoring the
saved thread context and decreasing the CSSA, it acts like EENTER which
doesn't decrease the CSSA but establishes a clean slate thread context
at the CSSA for the enclave to handle the notification.  After some
handling, the enclave must discard the "new-established" SSA and switch
back to the previous saved SSA (upon AEX).  Otherwise, the enclave will
run out of SSA space upon further AEXs and eventually fail to run.

To solve this problem, the new EDECCSSA essentially decreases the CSSA.
It can be used by the enclave notification handler to switch back to the
previous saved SSA when needed, i.e. after it handles the notification.

Signed-off-by: Kai Huang <kai.huang@intel.com>
---
Hi Dave,

This is the patch you requested.  Feel free to merge.

This patch isn't tested and needs KVM maintainers' review.

---
 arch/x86/include/asm/cpufeatures.h | 1 +
 arch/x86/kvm/cpuid.c               | 2 +-
 arch/x86/kvm/reverse_cpuid.h       | 3 +++
 3 files changed, 5 insertions(+), 1 deletion(-)

Comments

Huang, Kai Aug. 17, 2022, 9:49 a.m. UTC | #1
On Wed, 2022-07-27 at 23:54 +1200, Kai Huang wrote:
> Coupled with the new SGX attribute to allow one enclave to receive the
> AEX notification, SGX also adds a new EDECCSSA user leaf function to
> facilitate the AEX notification handling.  The new EDECCSSA is
> enumerated via CPUID(EAX=0x12,ECX=0x0):EAX[11].
> 
> Besides Allowing reporting the new AEX-notify attribute to KVM guests,
> also allow reporting the new EDECCSSA user leaf function to KVM guests
> so the guest can fully utilize the AEX-notify mechanism.
> 
> Introduce a new X86 CPU feature flag for the new EDECCSSA, and report it
> in KVM's supported CPUIDs so the userspace hypervisor (i.e. Qemu) can
> enable it for the guest.
> 
> Note there's no additional enabling work required to allow guest to use
> the new EDECCSSA.  KVM is not able to trap ENCLU anyway.
> 
> More background about how do AEX-notify and EDECCSSA work:
> 
> The new Asynchronous Exit (AEX) notification mechanism (AEX-notify)
> allows one enclave to receive a notification in the ERESUME after the
> enclave exit due to an AEX.  EDECCSSA is a new SGX user leaf function
> (ENCLU[EDECCSSA]) to facilitate the AEX notification handling.
> 
> SGX maintains a Current State Save Area Frame (CSSA) for each enclave
> thread.  When AEX happens, the enclave thread context is saved to the
> CSSA and the CSSA is increased by 1.  For a normal ERESUME which doesn't
> deliver AEX notification, it restores the saved thread context from the
> previously saved SSA and decreases the CSSA.  If AEX-notify is enabled
> for one enclave, the ERESUME acts differently.  Instead of restoring the
> saved thread context and decreasing the CSSA, it acts like EENTER which
> doesn't decrease the CSSA but establishes a clean slate thread context
> at the CSSA for the enclave to handle the notification.  After some
> handling, the enclave must discard the "new-established" SSA and switch
> back to the previous saved SSA (upon AEX).  Otherwise, the enclave will
> run out of SSA space upon further AEXs and eventually fail to run.
> 
> To solve this problem, the new EDECCSSA essentially decreases the CSSA.
> It can be used by the enclave notification handler to switch back to the
> previous saved SSA when needed, i.e. after it handles the notification.
> 
> Signed-off-by: Kai Huang <kai.huang@intel.com>
> ---
> Hi Dave,
> 
> This is the patch you requested.  Feel free to merge.
> 
> This patch isn't tested and needs KVM maintainers' review.

Sorry this patch has bugs.  I forgot to handle the new X86_FEATURE_SGX_EDECCSSA
bit in scattered CPUID handling (and forgot to add it to the CPUID dependency
table). Will send v2 after testing.
diff mbox series

Patch

diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index 6466a58b9cff..d2ebb38b31e7 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -296,6 +296,7 @@ 
 #define X86_FEATURE_PER_THREAD_MBA	(11*32+ 7) /* "" Per-thread Memory Bandwidth Allocation */
 #define X86_FEATURE_SGX1		(11*32+ 8) /* "" Basic SGX */
 #define X86_FEATURE_SGX2		(11*32+ 9) /* "" SGX Enclave Dynamic Memory Management (EDMM) */
+#define X86_FEATURE_SGX_EDECCSSA	(11*32+10) /* "" SGX EDECCSSA user leaf function */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
 #define X86_FEATURE_AVX_VNNI		(12*32+ 4) /* AVX VNNI instructions */
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 75dcf7a72605..c21b4a5dc8fa 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -644,7 +644,7 @@  void kvm_set_cpu_caps(void)
 	);
 
 	kvm_cpu_cap_init_scattered(CPUID_12_EAX,
-		SF(SGX1) | SF(SGX2)
+		SF(SGX1) | SF(SGX2) | SF(SGX_EDECCSSA)
 	);
 
 	kvm_cpu_cap_mask(CPUID_8000_0001_ECX,
diff --git a/arch/x86/kvm/reverse_cpuid.h b/arch/x86/kvm/reverse_cpuid.h
index a19d473d0184..4e5b8444f161 100644
--- a/arch/x86/kvm/reverse_cpuid.h
+++ b/arch/x86/kvm/reverse_cpuid.h
@@ -23,6 +23,7 @@  enum kvm_only_cpuid_leafs {
 /* Intel-defined SGX sub-features, CPUID level 0x12 (EAX). */
 #define KVM_X86_FEATURE_SGX1		KVM_X86_FEATURE(CPUID_12_EAX, 0)
 #define KVM_X86_FEATURE_SGX2		KVM_X86_FEATURE(CPUID_12_EAX, 1)
+#define KVM_X86_FEATURE_SGX_EDECCSSA	KVM_X86_FEATURE(CPUID_12_EAX, 11)
 
 struct cpuid_reg {
 	u32 function;
@@ -78,6 +79,8 @@  static __always_inline u32 __feature_translate(int x86_feature)
 		return KVM_X86_FEATURE_SGX1;
 	else if (x86_feature == X86_FEATURE_SGX2)
 		return KVM_X86_FEATURE_SGX2;
+	else if (x86_feature == X86_FEATURE_SGX_EDECCSSA)
+		return KVM_X86_FEATURE_SGX_EDECCSSA;
 
 	return x86_feature;
 }