Message ID | 148846768878.2349.15757532025749214650.stgit@brijesh-build-machine (mailing list archive) |
---|---|
State | Not Applicable |
Delegated to: | Herbert Xu |
Headers | show |
On Thu, Mar 02, 2017 at 10:14:48AM -0500, Brijesh Singh wrote: > From: Tom Lendacky <thomas.lendacky@amd.com> > > Early in the boot process, add checks to determine if the kernel is > running with Secure Encrypted Virtualization (SEV) active by issuing > a CPUID instruction. > > During early compressed kernel booting, if SEV is active the pagetables are > updated so that data is accessed and decompressed with encryption. > > During uncompressed kernel booting, if SEV is the memory encryption mask is > set and a flag is set to indicate that SEV is enabled. I don't know how many times I have to say this but I'm going to keep doing it until it sticks: :-) Please, no "WHAT" in the commit messages - I can see the "WHAT - but "WHY". Ok? > diff --git a/arch/x86/boot/compressed/mem_encrypt.S b/arch/x86/boot/compressed/mem_encrypt.S > new file mode 100644 > index 0000000..8313c31 > --- /dev/null > +++ b/arch/x86/boot/compressed/mem_encrypt.S > @@ -0,0 +1,75 @@ > +/* > + * AMD Memory Encryption Support > + * > + * Copyright (C) 2016 Advanced Micro Devices, Inc. > + * > + * Author: Tom Lendacky <thomas.lendacky@amd.com> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + */ > + > +#include <linux/linkage.h> > + > +#include <asm/processor-flags.h> > +#include <asm/msr.h> > +#include <asm/asm-offsets.h> > +#include <uapi/asm/kvm_para.h> > + > + .text > + .code32 > +ENTRY(sev_enabled) > + xor %eax, %eax > + > +#ifdef CONFIG_AMD_MEM_ENCRYPT > + push %ebx > + push %ecx > + push %edx > + > + /* Check if running under a hypervisor */ > + movl $0x40000000, %eax > + cpuid > + cmpl $0x40000001, %eax > + jb .Lno_sev > + > + movl $0x40000001, %eax > + cpuid > + bt $KVM_FEATURE_SEV, %eax > + jnc .Lno_sev > + > + /* > + * Check for memory encryption feature: > + * CPUID Fn8000_001F[EAX] - Bit 0 > + */ > + movl $0x8000001f, %eax > + cpuid > + bt $0, %eax > + jnc .Lno_sev > + > + /* > + * Get memory encryption information: > + * CPUID Fn8000_001F[EBX] - Bits 5:0 > + * Pagetable bit position used to indicate encryption > + */ > + movl %ebx, %eax > + andl $0x3f, %eax > + movl %eax, sev_enc_bit(%ebp) > + jmp .Lsev_exit > + > +.Lno_sev: > + xor %eax, %eax > + > +.Lsev_exit: > + pop %edx > + pop %ecx > + pop %ebx > + > +#endif /* CONFIG_AMD_MEM_ENCRYPT */ > + > + ret > +ENDPROC(sev_enabled) Right, as said in another mail earlier, this could be written in C. And then the sme_enable() piece below looks the same as this one above. So since you want to run it before kernel decompression and after, you could extract this code into a separate .c file which you can link in both places, similar to what we do with verify_cpu with the difference that verify_cpu is getting included. Alternatively, we still have some room in setup_header.xloadflags to pass boot info to kernel proper from before the decompression stage. But I'd prefer linking with both stages as it is cheaper and those flags we can use for something which really wants to use a flag like that. > diff --git a/arch/x86/kernel/mem_encrypt_init.c b/arch/x86/kernel/mem_encrypt_init.c > index 35c5e3d..5d514e6 100644 > --- a/arch/x86/kernel/mem_encrypt_init.c > +++ b/arch/x86/kernel/mem_encrypt_init.c > @@ -22,6 +22,7 @@ > #include <asm/processor-flags.h> > #include <asm/msr.h> > #include <asm/cmdline.h> > +#include <asm/kvm_para.h> > > static char sme_cmdline_arg_on[] __initdata = "mem_encrypt=on"; > static char sme_cmdline_arg_off[] __initdata = "mem_encrypt=off"; > @@ -232,6 +233,29 @@ unsigned long __init sme_enable(void *boot_data) > void *cmdline_arg; > u64 msr; > > + /* Check if running under a hypervisor */ > + eax = 0x40000000; > + ecx = 0; > + native_cpuid(&eax, &ebx, &ecx, &edx); > + if (eax > 0x40000000) { > + eax = 0x40000001; > + ecx = 0; > + native_cpuid(&eax, &ebx, &ecx, &edx); > + if (!(eax & BIT(KVM_FEATURE_SEV))) > + goto out; > + > + eax = 0x8000001f; > + ecx = 0; > + native_cpuid(&eax, &ebx, &ecx, &edx); > + if (!(eax & 1)) > + goto out; > + > + sme_me_mask = 1UL << (ebx & 0x3f); > + sev_enabled = 1; > + > + goto out; > + } > + > /* Check for an AMD processor */ > eax = 0; > ecx = 0; >
On 09/03/2017 15:07, Borislav Petkov wrote: > + /* Check if running under a hypervisor */ > + eax = 0x40000000; > + ecx = 0; > + native_cpuid(&eax, &ebx, &ecx, &edx); This is not how you check if running under a hypervisor; you should check the HYPERVISOR bit, i.e. bit 31 of cpuid(1).ecx. This in turn tells you if leaf 0x40000000 is valid. That said, the main issue with this function is that it hardcodes the behavior for KVM. It is possible that another hypervisor defines its 0x40000001 leaf in such a way that KVM_FEATURE_SEV has a different meaning. Instead, AMD should define a "well-known" bit in its own space (i.e. 0x800000xx) that is only used by hypervisors that support SEV. This is similar to how Intel defined one bit in leaf 1 to say "is leaf 0x40000000 valid". Thanks, Paolo > + if (eax > 0x40000000) { > + eax = 0x40000001; > + ecx = 0; > + native_cpuid(&eax, &ebx, &ecx, &edx); > + if (!(eax & BIT(KVM_FEATURE_SEV))) > + goto out; > + > + eax = 0x8000001f; > + ecx = 0; > + native_cpuid(&eax, &ebx, &ecx, &edx); > + if (!(eax & 1)) > + goto out; > + > + sme_me_mask = 1UL << (ebx & 0x3f); > + sev_enabled = 1; > + > + goto out; > + } > +
On Thu, Mar 09, 2017 at 05:13:33PM +0100, Paolo Bonzini wrote: > This is not how you check if running under a hypervisor; you should > check the HYPERVISOR bit, i.e. bit 31 of cpuid(1).ecx. This in turn > tells you if leaf 0x40000000 is valid. Ah, good point, I already do that in the microcode loader :) /* * CPUID(1).ECX[31]: reserved for hypervisor use. This is still not * completely accurate as xen pv guests don't see that CPUID bit set but * that's good enough as they don't land on the BSP path anyway. */ if (native_cpuid_ecx(1) & BIT(31)) return *res; > That said, the main issue with this function is that it hardcodes the > behavior for KVM. It is possible that another hypervisor defines its > 0x40000001 leaf in such a way that KVM_FEATURE_SEV has a different meaning. > > Instead, AMD should define a "well-known" bit in its own space (i.e. > 0x800000xx) that is only used by hypervisors that support SEV. This is > similar to how Intel defined one bit in leaf 1 to say "is leaf > 0x40000000 valid". > > > + if (eax > 0x40000000) { > > + eax = 0x40000001; > > + ecx = 0; > > + native_cpuid(&eax, &ebx, &ecx, &edx); > > + if (!(eax & BIT(KVM_FEATURE_SEV))) > > + goto out; > > + > > + eax = 0x8000001f; > > + ecx = 0; > > + native_cpuid(&eax, &ebx, &ecx, &edx); > > + if (!(eax & 1)) Right, so this is testing CPUID_0x8000001f_ECX(0)[0], SME. Why not simply set that bit for the guest too, in kvm?
Hi Boris and Paolo, On 03/09/2017 10:29 AM, Borislav Petkov wrote: > On Thu, Mar 09, 2017 at 05:13:33PM +0100, Paolo Bonzini wrote: >> This is not how you check if running under a hypervisor; you should >> check the HYPERVISOR bit, i.e. bit 31 of cpuid(1).ecx. This in turn >> tells you if leaf 0x40000000 is valid. > > Ah, good point, I already do that in the microcode loader :) > > /* > * CPUID(1).ECX[31]: reserved for hypervisor use. This is still not > * completely accurate as xen pv guests don't see that CPUID bit set but > * that's good enough as they don't land on the BSP path anyway. > */ > if (native_cpuid_ecx(1) & BIT(31)) > return *res; > >> That said, the main issue with this function is that it hardcodes the >> behavior for KVM. It is possible that another hypervisor defines its >> 0x40000001 leaf in such a way that KVM_FEATURE_SEV has a different meaning. >> >> Instead, AMD should define a "well-known" bit in its own space (i.e. >> 0x800000xx) that is only used by hypervisors that support SEV. This is >> similar to how Intel defined one bit in leaf 1 to say "is leaf >> 0x40000000 valid". >> >>> + if (eax > 0x40000000) { >>> + eax = 0x40000001; >>> + ecx = 0; >>> + native_cpuid(&eax, &ebx, &ecx, &edx); >>> + if (!(eax & BIT(KVM_FEATURE_SEV))) >>> + goto out; >>> + >>> + eax = 0x8000001f; >>> + ecx = 0; >>> + native_cpuid(&eax, &ebx, &ecx, &edx); >>> + if (!(eax & 1)) > > Right, so this is testing CPUID_0x8000001f_ECX(0)[0], SME. Why not > simply set that bit for the guest too, in kvm? > CPUID_8000_001F[EAX] indicates whether the feature is supported. CPUID_0x8000001F[EAX]: * Bit 0 - SME supported * Bit 1 - SEV supported * Bit 3 - SEV-ES supported We can use MSR_K8_SYSCFG[MemEncryptionModeEnc] to check if memory encryption is enabled. Currently, KVM returns zero when guest OS read MSR_K8_SYSCFG. I can update my patch sets to set this bit for SEV enabled guests. We could update this patch to use the below logic: * CPUID(0) - Check for AuthenticAMD * CPID(1) - Check if under hypervisor * CPUID(0x80000000) - Check for highest supported leaf * CPUID(0x8000001F).EAX - Check for SME and SEV support * rdmsr (MSR_K8_SYSCFG)[MemEncryptionModeEnc] - Check if SMEE is set Paolo, One question, do we need "AuthenticAMD" check when we are running under hypervisor ? I was looking at qemu code and found that qemu exposes parameters to change the CPU vendor id. The above check will fail if user changes the vendor id while launching the SEV guest. -Brijesh
On Fri, Mar 10, 2017 at 10:35:30AM -0600, Brijesh Singh wrote: > We could update this patch to use the below logic: > > * CPUID(0) - Check for AuthenticAMD > * CPID(1) - Check if under hypervisor > * CPUID(0x80000000) - Check for highest supported leaf > * CPUID(0x8000001F).EAX - Check for SME and SEV support > * rdmsr (MSR_K8_SYSCFG)[MemEncryptionModeEnc] - Check if SMEE is set Actually, it is still not clear to me *why* we need to do anything special wrt SEV in the guest. Lemme clarify: why can't the guest boot just like a normal Linux on baremetal and use the SME(!) detection code to set sme_enable and so on? IOW, I'd like to avoid all those checks whether we're running under hypervisor and handle all that like we're running on baremetal.
On 3/16/2017 5:16 AM, Borislav Petkov wrote: > On Fri, Mar 10, 2017 at 10:35:30AM -0600, Brijesh Singh wrote: >> We could update this patch to use the below logic: >> >> * CPUID(0) - Check for AuthenticAMD >> * CPID(1) - Check if under hypervisor >> * CPUID(0x80000000) - Check for highest supported leaf >> * CPUID(0x8000001F).EAX - Check for SME and SEV support >> * rdmsr (MSR_K8_SYSCFG)[MemEncryptionModeEnc] - Check if SMEE is set > > Actually, it is still not clear to me *why* we need to do anything > special wrt SEV in the guest. > > Lemme clarify: why can't the guest boot just like a normal Linux on > baremetal and use the SME(!) detection code to set sme_enable and so > on? IOW, I'd like to avoid all those checks whether we're running under > hypervisor and handle all that like we're running on baremetal. Because there are differences between how SME and SEV behave (instruction fetches are always decrypted under SEV, DMA to an encrypted location is not supported under SEV, etc.) we need to determine which mode we are in so that things can be setup properly during boot. For example, if SEV is active the kernel will already be encrypted and so we don't perform that step or the trampoline area for bringing up an AP must be decrypted for SME but encrypted for SEV. The hypervisor check will provide that ability to determine how we handle things. Thanks, Tom >
On Thu, Mar 16, 2017 at 09:28:58AM -0500, Tom Lendacky wrote: > Because there are differences between how SME and SEV behave > (instruction fetches are always decrypted under SEV, DMA to an > encrypted location is not supported under SEV, etc.) we need to > determine which mode we are in so that things can be setup properly > during boot. For example, if SEV is active the kernel will already > be encrypted and so we don't perform that step or the trampoline area > for bringing up an AP must be decrypted for SME but encrypted for SEV. So with SEV enabled, it seems to me a guest doesn't know anything about encryption and can run as if SME is disabled. So sme_active() will be false. And then the kernel can bypass all that code dealing with SME. So a guest should simply run like on baremetal with no SME, IMHO. But then there's that part: "instruction fetches are always decrypted under SEV". What does that mean exactly? And how much of that code can be reused so that * SME on baremetal * SEV on guest use the same logic? Having the larger SEV preparation part on the kvm host side is perfectly fine. But I'd like to keep kernel initialization paths clean. Thanks.
On 3/16/2017 10:09 AM, Borislav Petkov wrote: > On Thu, Mar 16, 2017 at 09:28:58AM -0500, Tom Lendacky wrote: >> Because there are differences between how SME and SEV behave >> (instruction fetches are always decrypted under SEV, DMA to an >> encrypted location is not supported under SEV, etc.) we need to >> determine which mode we are in so that things can be setup properly >> during boot. For example, if SEV is active the kernel will already >> be encrypted and so we don't perform that step or the trampoline area >> for bringing up an AP must be decrypted for SME but encrypted for SEV. > > So with SEV enabled, it seems to me a guest doesn't know anything about > encryption and can run as if SME is disabled. So sme_active() will be > false. And then the kernel can bypass all that code dealing with SME. > > So a guest should simply run like on baremetal with no SME, IMHO. > Not quite. The guest still needs to understand about the encryption mask so that it can protect memory by setting the encryption mask in the pagetable entries. It can also decide when to share memory with the hypervisor by not setting the encryption mask in the pagetable entries. > But then there's that part: "instruction fetches are always decrypted > under SEV". What does that mean exactly? And how much of that code can "Instruction fetches are always decrypted under SEV" means that, regardless of how a virtual address is mapped, encrypted or decrypted, if an instruction fetch is performed by the CPU from that address it will always be decrypted. This is to prevent the hypervisor from injecting executable code into the guest since it would have to be valid encrypted instructions. > be reused so that > > * SME on baremetal > * SEV on guest > > use the same logic? There are many areas that use the same logic, but there are certain situations where we need to check between SME vs SEV (e.g. DMA operation setup or decrypting the trampoline area) and act accordingly. Thanks, Tom > > Having the larger SEV preparation part on the kvm host side is perfectly > fine. But I'd like to keep kernel initialization paths clean. > > Thanks. >
On Thu, Mar 16, 2017 at 11:11:26AM -0500, Tom Lendacky wrote: > Not quite. The guest still needs to understand about the encryption mask > so that it can protect memory by setting the encryption mask in the > pagetable entries. It can also decide when to share memory with the > hypervisor by not setting the encryption mask in the pagetable entries. Ok, so the kernel - by that I mean both the baremetal and guest kernel - needs to know whether we're encrypting stuff. So it needs to know about SME. > "Instruction fetches are always decrypted under SEV" means that, > regardless of how a virtual address is mapped, encrypted or decrypted, > if an instruction fetch is performed by the CPU from that address it > will always be decrypted. This is to prevent the hypervisor from > injecting executable code into the guest since it would have to be > valid encrypted instructions. Ok, so the guest needs to map its pages encrypted. Which reminds me, KSM might be a PITA to enable with SEV but that's a different story. :) > There are many areas that use the same logic, but there are certain > situations where we need to check between SME vs SEV (e.g. DMA operation > setup or decrypting the trampoline area) and act accordingly. Right, and I'd like to keep those areas where it differs at minimum and nicely cordoned off from the main paths. So looking back at the current patch in this subthread: we do check * CPUID 0x40000000 * 8000_001F[EAX] for SME * 8000_001F[EBX][5:0] for the encryption bits. So how about we generate the following CPUID picture for the guest: CPUID_Fn8000001F_EAX = ...10b That is, SME bit is cleared, SEV is set. This will mean for the guest kernel that SEV is enabled and you can avoid yourself the 0x40000000 leaf check and the additional KVM feature bit glue. 10b configuration will be invalid for baremetal as - I'm assuming - you can't have SEV=1b with SME=0b. It will be a virt-only configuration and this way you can even avoid the hypervisor-specific detection but do that for all. Hmmm?
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 44163e8..51f9cd0 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -72,6 +72,8 @@ vmlinux-objs-y := $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \ $(obj)/string.o $(obj)/cmdline.o $(obj)/error.o \ $(obj)/piggy.o $(obj)/cpuflags.o +vmlinux-objs-$(CONFIG_X86_64) += $(obj)/mem_encrypt.o + vmlinux-objs-$(CONFIG_EARLY_PRINTK) += $(obj)/early_serial_console.o vmlinux-objs-$(CONFIG_RANDOMIZE_BASE) += $(obj)/kaslr.o ifdef CONFIG_X86_64 diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S index d2ae1f8..625b5380 100644 --- a/arch/x86/boot/compressed/head_64.S +++ b/arch/x86/boot/compressed/head_64.S @@ -130,6 +130,19 @@ ENTRY(startup_32) /* * Build early 4G boot pagetable */ + /* + * If SEV is active set the encryption mask in the page tables. This + * will insure that when the kernel is copied and decompressed it + * will be done so encrypted. + */ + call sev_enabled + xorl %edx, %edx + testl %eax, %eax + jz 1f + subl $32, %eax /* Encryption bit is always above bit 31 */ + bts %eax, %edx /* Set encryption mask for page tables */ +1: + /* Initialize Page tables to 0 */ leal pgtable(%ebx), %edi xorl %eax, %eax @@ -140,12 +153,14 @@ ENTRY(startup_32) leal pgtable + 0(%ebx), %edi leal 0x1007 (%edi), %eax movl %eax, 0(%edi) + addl %edx, 4(%edi) /* Build Level 3 */ leal pgtable + 0x1000(%ebx), %edi leal 0x1007(%edi), %eax movl $4, %ecx 1: movl %eax, 0x00(%edi) + addl %edx, 0x04(%edi) addl $0x00001000, %eax addl $8, %edi decl %ecx @@ -156,6 +171,7 @@ ENTRY(startup_32) movl $0x00000183, %eax movl $2048, %ecx 1: movl %eax, 0(%edi) + addl %edx, 4(%edi) addl $0x00200000, %eax addl $8, %edi decl %ecx diff --git a/arch/x86/boot/compressed/mem_encrypt.S b/arch/x86/boot/compressed/mem_encrypt.S new file mode 100644 index 0000000..8313c31 --- /dev/null +++ b/arch/x86/boot/compressed/mem_encrypt.S @@ -0,0 +1,75 @@ +/* + * AMD Memory Encryption Support + * + * Copyright (C) 2016 Advanced Micro Devices, Inc. + * + * Author: Tom Lendacky <thomas.lendacky@amd.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/linkage.h> + +#include <asm/processor-flags.h> +#include <asm/msr.h> +#include <asm/asm-offsets.h> +#include <uapi/asm/kvm_para.h> + + .text + .code32 +ENTRY(sev_enabled) + xor %eax, %eax + +#ifdef CONFIG_AMD_MEM_ENCRYPT + push %ebx + push %ecx + push %edx + + /* Check if running under a hypervisor */ + movl $0x40000000, %eax + cpuid + cmpl $0x40000001, %eax + jb .Lno_sev + + movl $0x40000001, %eax + cpuid + bt $KVM_FEATURE_SEV, %eax + jnc .Lno_sev + + /* + * Check for memory encryption feature: + * CPUID Fn8000_001F[EAX] - Bit 0 + */ + movl $0x8000001f, %eax + cpuid + bt $0, %eax + jnc .Lno_sev + + /* + * Get memory encryption information: + * CPUID Fn8000_001F[EBX] - Bits 5:0 + * Pagetable bit position used to indicate encryption + */ + movl %ebx, %eax + andl $0x3f, %eax + movl %eax, sev_enc_bit(%ebp) + jmp .Lsev_exit + +.Lno_sev: + xor %eax, %eax + +.Lsev_exit: + pop %edx + pop %ecx + pop %ebx + +#endif /* CONFIG_AMD_MEM_ENCRYPT */ + + ret +ENDPROC(sev_enabled) + + .bss +sev_enc_bit: + .word 0 diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h index 9b1a918..8278161 100644 --- a/arch/x86/include/uapi/asm/hyperv.h +++ b/arch/x86/include/uapi/asm/hyperv.h @@ -3,6 +3,8 @@ #include <linux/types.h> +#ifndef __ASSEMBLY__ + /* * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent * is set by CPUID(HvCpuIdFunctionVersionAndFeatures). @@ -363,4 +365,6 @@ struct hv_timer_message_payload { #define HV_STIMER_AUTOENABLE (1ULL << 3) #define HV_STIMER_SINT(config) (__u8)(((config) >> 16) & 0x0F) +#endif /* __ASSEMBLY__ */ + #endif diff --git a/arch/x86/include/uapi/asm/kvm_para.h b/arch/x86/include/uapi/asm/kvm_para.h index bc2802f..e81b74a 100644 --- a/arch/x86/include/uapi/asm/kvm_para.h +++ b/arch/x86/include/uapi/asm/kvm_para.h @@ -26,6 +26,8 @@ #define KVM_FEATURE_PV_UNHALT 7 #define KVM_FEATURE_SEV 8 +#ifndef __ASSEMBLY__ + /* The last 8 bits are used to indicate how to interpret the flags field * in pvclock structure. If no bits are set, all flags are ignored. */ @@ -100,5 +102,6 @@ struct kvm_vcpu_pv_apf_data { #define KVM_PV_EOI_ENABLED KVM_PV_EOI_MASK #define KVM_PV_EOI_DISABLED 0x0 +#endif /* __ASSEMBLY__ */ #endif /* _UAPI_ASM_X86_KVM_PARA_H */ diff --git a/arch/x86/kernel/mem_encrypt_init.c b/arch/x86/kernel/mem_encrypt_init.c index 35c5e3d..5d514e6 100644 --- a/arch/x86/kernel/mem_encrypt_init.c +++ b/arch/x86/kernel/mem_encrypt_init.c @@ -22,6 +22,7 @@ #include <asm/processor-flags.h> #include <asm/msr.h> #include <asm/cmdline.h> +#include <asm/kvm_para.h> static char sme_cmdline_arg_on[] __initdata = "mem_encrypt=on"; static char sme_cmdline_arg_off[] __initdata = "mem_encrypt=off"; @@ -232,6 +233,29 @@ unsigned long __init sme_enable(void *boot_data) void *cmdline_arg; u64 msr; + /* Check if running under a hypervisor */ + eax = 0x40000000; + ecx = 0; + native_cpuid(&eax, &ebx, &ecx, &edx); + if (eax > 0x40000000) { + eax = 0x40000001; + ecx = 0; + native_cpuid(&eax, &ebx, &ecx, &edx); + if (!(eax & BIT(KVM_FEATURE_SEV))) + goto out; + + eax = 0x8000001f; + ecx = 0; + native_cpuid(&eax, &ebx, &ecx, &edx); + if (!(eax & 1)) + goto out; + + sme_me_mask = 1UL << (ebx & 0x3f); + sev_enabled = 1; + + goto out; + } + /* Check for an AMD processor */ eax = 0; ecx = 0;