Message ID | 87cz2ija1e.ffs@tglx (mailing list archive) |
---|---|
State | Handled Elsewhere |
Headers | show |
Series | x86/smpboot: Disable parallel bootup if cc_vendor != NONE | expand |
On Tue, May 30, 2023 at 02:09:17PM +0200, Thomas Gleixner wrote: > The decision to allow parallel bringup of secondary CPUs checks > CC_ATTR_GUEST_STATE_ENCRYPT to detect encrypted guests. Those cannot use > parallel bootup because accessing the local APIC is intercepted and raises > a #VC or #VE, which cannot be handled at that point. > > The check works correctly, but only for AMD encrypted guests. TDX does not > set that flag. > > Check for cc_vendor != CC_VENDOR_NONE instead. That might be overbroad, but > definitely works for both AMD and Intel. It boots fine with TDX, but I think it is wrong. cc_get_vendor() will report CC_VENDOR_AMD even on bare metal if SME is enabled. I don't think we want it.
On Tue, May 30 2023 at 15:29, Kirill A. Shutemov wrote: > On Tue, May 30, 2023 at 02:09:17PM +0200, Thomas Gleixner wrote: >> The decision to allow parallel bringup of secondary CPUs checks >> CC_ATTR_GUEST_STATE_ENCRYPT to detect encrypted guests. Those cannot use >> parallel bootup because accessing the local APIC is intercepted and raises >> a #VC or #VE, which cannot be handled at that point. >> >> The check works correctly, but only for AMD encrypted guests. TDX does not >> set that flag. >> >> Check for cc_vendor != CC_VENDOR_NONE instead. That might be overbroad, but >> definitely works for both AMD and Intel. > > It boots fine with TDX, but I think it is wrong. cc_get_vendor() will > report CC_VENDOR_AMD even on bare metal if SME is enabled. I don't think > we want it. Right. Did not think about that. But the same way is CC_ATTR_GUEST_MEM_ENCRYPT overbroad for AMD. Only SEV-ES traps RDMSR if I'm understandig that maze correctly. Thanks, tglx
On Tue, May 30, 2023, Thomas Gleixner wrote: > On Tue, May 30 2023 at 15:29, Kirill A. Shutemov wrote: > > On Tue, May 30, 2023 at 02:09:17PM +0200, Thomas Gleixner wrote: > >> The decision to allow parallel bringup of secondary CPUs checks > >> CC_ATTR_GUEST_STATE_ENCRYPT to detect encrypted guests. Those cannot use > >> parallel bootup because accessing the local APIC is intercepted and raises > >> a #VC or #VE, which cannot be handled at that point. > >> > >> The check works correctly, but only for AMD encrypted guests. TDX does not > >> set that flag. > >> > >> Check for cc_vendor != CC_VENDOR_NONE instead. That might be overbroad, but > >> definitely works for both AMD and Intel. > > > > It boots fine with TDX, but I think it is wrong. cc_get_vendor() will > > report CC_VENDOR_AMD even on bare metal if SME is enabled. I don't think > > we want it. > > Right. Did not think about that. > > But the same way is CC_ATTR_GUEST_MEM_ENCRYPT overbroad for AMD. Only > SEV-ES traps RDMSR if I'm understandig that maze correctly. Ya, regular SEV doesn't encrypt register state.
On Tue, May 30, 2023 at 06:00:46PM +0200, Thomas Gleixner wrote: > On Tue, May 30 2023 at 15:29, Kirill A. Shutemov wrote: > > On Tue, May 30, 2023 at 02:09:17PM +0200, Thomas Gleixner wrote: > >> The decision to allow parallel bringup of secondary CPUs checks > >> CC_ATTR_GUEST_STATE_ENCRYPT to detect encrypted guests. Those cannot use > >> parallel bootup because accessing the local APIC is intercepted and raises > >> a #VC or #VE, which cannot be handled at that point. > >> > >> The check works correctly, but only for AMD encrypted guests. TDX does not > >> set that flag. > >> > >> Check for cc_vendor != CC_VENDOR_NONE instead. That might be overbroad, but > >> definitely works for both AMD and Intel. > > > > It boots fine with TDX, but I think it is wrong. cc_get_vendor() will > > report CC_VENDOR_AMD even on bare metal if SME is enabled. I don't think > > we want it. > > Right. Did not think about that. > > But the same way is CC_ATTR_GUEST_MEM_ENCRYPT overbroad for AMD. Only > SEV-ES traps RDMSR if I'm understandig that maze correctly. I don't know difference between SEV flavours that well. I see there's that on SEV-SNP access to x2APIC MSR range (MSR 0x800-0x8FF) is intercepted regardless if MSR_AMD64_SNP_ALT_INJ feature is present. But I'm not sure what the state on SEV or SEV-ES. Tom?
On Tue, May 30, 2023, Kirill A. Shutemov wrote: > On Tue, May 30, 2023 at 06:00:46PM +0200, Thomas Gleixner wrote: > > On Tue, May 30 2023 at 15:29, Kirill A. Shutemov wrote: > > > On Tue, May 30, 2023 at 02:09:17PM +0200, Thomas Gleixner wrote: > > >> The decision to allow parallel bringup of secondary CPUs checks > > >> CC_ATTR_GUEST_STATE_ENCRYPT to detect encrypted guests. Those cannot use > > >> parallel bootup because accessing the local APIC is intercepted and raises > > >> a #VC or #VE, which cannot be handled at that point. > > >> > > >> The check works correctly, but only for AMD encrypted guests. TDX does not > > >> set that flag. > > >> > > >> Check for cc_vendor != CC_VENDOR_NONE instead. That might be overbroad, but > > >> definitely works for both AMD and Intel. > > > > > > It boots fine with TDX, but I think it is wrong. cc_get_vendor() will > > > report CC_VENDOR_AMD even on bare metal if SME is enabled. I don't think > > > we want it. > > > > Right. Did not think about that. > > > > But the same way is CC_ATTR_GUEST_MEM_ENCRYPT overbroad for AMD. Only > > SEV-ES traps RDMSR if I'm understandig that maze correctly. > > I don't know difference between SEV flavours that well. > > I see there's that on SEV-SNP access to x2APIC MSR range (MSR 0x800-0x8FF) > is intercepted regardless if MSR_AMD64_SNP_ALT_INJ feature is present. But > I'm not sure what the state on SEV or SEV-ES. With SEV-ES, if the hypervisor intercepts an MSR access, the VM-Exit is instead morphed to a #VC (except for EFER). The guest needs to do an explicit VMGEXIT (i.e. a hypercall) to explicitly request MSR emulation (this *can* be done in the #VC handler, but the guest can also do VMGEXIT directly, e.g. in lieu of a RDMSR). With regular SEV, VM-Exits aren't reflected into the guest. Register state isn't encrypted so the hypervisor can emulate MSR accesses (and other instructions) without needing an explicit hypercall from the guest.
On Tue, May 30 2023 at 09:56, Sean Christopherson wrote: > On Tue, May 30, 2023, Thomas Gleixner wrote: >> On Tue, May 30 2023 at 15:29, Kirill A. Shutemov wrote: >> > On Tue, May 30, 2023 at 02:09:17PM +0200, Thomas Gleixner wrote: >> >> The decision to allow parallel bringup of secondary CPUs checks >> >> CC_ATTR_GUEST_STATE_ENCRYPT to detect encrypted guests. Those cannot use >> >> parallel bootup because accessing the local APIC is intercepted and raises >> >> a #VC or #VE, which cannot be handled at that point. >> >> >> >> The check works correctly, but only for AMD encrypted guests. TDX does not >> >> set that flag. >> >> >> >> Check for cc_vendor != CC_VENDOR_NONE instead. That might be overbroad, but >> >> definitely works for both AMD and Intel. >> > >> > It boots fine with TDX, but I think it is wrong. cc_get_vendor() will >> > report CC_VENDOR_AMD even on bare metal if SME is enabled. I don't think >> > we want it. >> >> Right. Did not think about that. >> >> But the same way is CC_ATTR_GUEST_MEM_ENCRYPT overbroad for AMD. Only >> SEV-ES traps RDMSR if I'm understandig that maze correctly. > > Ya, regular SEV doesn't encrypt register state. That aside. From a semantical POV making this decision about parallel bootup based on some magic CC encryption attribute is questionable. I'm tending to just do the below and make this CC agnostic (except that I couldn't find the right spot for SEV-ES to clear that flag.) Thanks, tglx --- --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -871,5 +871,7 @@ void __init tdx_early_init(void) x86_platform.guest.enc_tlb_flush_required = tdx_tlb_flush_required; x86_platform.guest.enc_status_change_finish = tdx_enc_status_changed; + x86_cpuinit.parallel_bringup = false; + pr_info("Guest detected\n"); } --- a/arch/x86/include/asm/x86_init.h +++ b/arch/x86/include/asm/x86_init.h @@ -2,6 +2,7 @@ #ifndef _ASM_X86_PLATFORM_H #define _ASM_X86_PLATFORM_H +#include <linux/bits.h> #include <asm/bootparam.h> struct ghcb; @@ -177,11 +178,14 @@ struct x86_init_ops { * struct x86_cpuinit_ops - platform specific cpu hotplug setups * @setup_percpu_clockev: set up the per cpu clock event device * @early_percpu_clock_init: early init of the per cpu clock event device + * @fixup_cpu_id: fixup function for cpuinfo_x86::phys_proc_id + * @parallel_bringup: Parallel bringup control */ struct x86_cpuinit_ops { void (*setup_percpu_clockev)(void); void (*early_percpu_clock_init)(void); void (*fixup_cpu_id)(struct cpuinfo_x86 *c, int node); + bool parallel_bringup; }; struct timespec64; --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -1287,6 +1287,11 @@ bool __init arch_cpuhp_init_parallel_bri return false; } + if (!x86_cpuinit.parallel_bringup) { + pr_info("Parallel CPU startup disabled by the platform\n"); + return false; + } + smpboot_control = STARTUP_READ_APICID; pr_debug("Parallel CPU startup enabled: 0x%08x\n", smpboot_control); return true; --- a/arch/x86/kernel/x86_init.c +++ b/arch/x86/kernel/x86_init.c @@ -126,6 +126,7 @@ struct x86_init_ops x86_init __initdata struct x86_cpuinit_ops x86_cpuinit = { .early_percpu_clock_init = x86_init_noop, .setup_percpu_clockev = setup_secondary_APIC_clock, + .parallel_bringup = true, }; static void default_nmi_init(void) { };
On 5/30/23 14:51, Thomas Gleixner wrote: > On Tue, May 30 2023 at 09:56, Sean Christopherson wrote: >> On Tue, May 30, 2023, Thomas Gleixner wrote: >>> On Tue, May 30 2023 at 15:29, Kirill A. Shutemov wrote: >>>> On Tue, May 30, 2023 at 02:09:17PM +0200, Thomas Gleixner wrote: >>>>> The decision to allow parallel bringup of secondary CPUs checks >>>>> CC_ATTR_GUEST_STATE_ENCRYPT to detect encrypted guests. Those cannot use >>>>> parallel bootup because accessing the local APIC is intercepted and raises >>>>> a #VC or #VE, which cannot be handled at that point. >>>>> >>>>> The check works correctly, but only for AMD encrypted guests. TDX does not >>>>> set that flag. >>>>> >>>>> Check for cc_vendor != CC_VENDOR_NONE instead. That might be overbroad, but >>>>> definitely works for both AMD and Intel. >>>> >>>> It boots fine with TDX, but I think it is wrong. cc_get_vendor() will >>>> report CC_VENDOR_AMD even on bare metal if SME is enabled. I don't think >>>> we want it. >>> >>> Right. Did not think about that. >>> >>> But the same way is CC_ATTR_GUEST_MEM_ENCRYPT overbroad for AMD. Only >>> SEV-ES traps RDMSR if I'm understandig that maze correctly. >> >> Ya, regular SEV doesn't encrypt register state. > > That aside. From a semantical POV making this decision about parallel > bootup based on some magic CC encryption attribute is questionable. > > I'm tending to just do the below and make this CC agnostic (except that > I couldn't find the right spot for SEV-ES to clear that flag.) Maybe in sme_sev_setup_real_mode() in arch/x86/realmode/init.c? You could clear the flag within the CC_ATTR_GUEST_STATE_ENCRYPT check. Thanks, Tom > > Thanks, > > tglx > --- > --- a/arch/x86/coco/tdx/tdx.c > +++ b/arch/x86/coco/tdx/tdx.c > @@ -871,5 +871,7 @@ void __init tdx_early_init(void) > x86_platform.guest.enc_tlb_flush_required = tdx_tlb_flush_required; > x86_platform.guest.enc_status_change_finish = tdx_enc_status_changed; > > + x86_cpuinit.parallel_bringup = false; > + > pr_info("Guest detected\n"); > } > --- a/arch/x86/include/asm/x86_init.h > +++ b/arch/x86/include/asm/x86_init.h > @@ -2,6 +2,7 @@ > #ifndef _ASM_X86_PLATFORM_H > #define _ASM_X86_PLATFORM_H > > +#include <linux/bits.h> > #include <asm/bootparam.h> > > struct ghcb; > @@ -177,11 +178,14 @@ struct x86_init_ops { > * struct x86_cpuinit_ops - platform specific cpu hotplug setups > * @setup_percpu_clockev: set up the per cpu clock event device > * @early_percpu_clock_init: early init of the per cpu clock event device > + * @fixup_cpu_id: fixup function for cpuinfo_x86::phys_proc_id > + * @parallel_bringup: Parallel bringup control > */ > struct x86_cpuinit_ops { > void (*setup_percpu_clockev)(void); > void (*early_percpu_clock_init)(void); > void (*fixup_cpu_id)(struct cpuinfo_x86 *c, int node); > + bool parallel_bringup; > }; > > struct timespec64; > --- a/arch/x86/kernel/smpboot.c > +++ b/arch/x86/kernel/smpboot.c > @@ -1287,6 +1287,11 @@ bool __init arch_cpuhp_init_parallel_bri > return false; > } > > + if (!x86_cpuinit.parallel_bringup) { > + pr_info("Parallel CPU startup disabled by the platform\n"); > + return false; > + } > + > smpboot_control = STARTUP_READ_APICID; > pr_debug("Parallel CPU startup enabled: 0x%08x\n", smpboot_control); > return true; > --- a/arch/x86/kernel/x86_init.c > +++ b/arch/x86/kernel/x86_init.c > @@ -126,6 +126,7 @@ struct x86_init_ops x86_init __initdata > struct x86_cpuinit_ops x86_cpuinit = { > .early_percpu_clock_init = x86_init_noop, > .setup_percpu_clockev = setup_secondary_APIC_clock, > + .parallel_bringup = true, > }; > > static void default_nmi_init(void) { };
On Tue, May 30 2023 at 15:03, Tom Lendacky wrote: > On 5/30/23 14:51, Thomas Gleixner wrote: >> That aside. From a semantical POV making this decision about parallel >> bootup based on some magic CC encryption attribute is questionable. >> >> I'm tending to just do the below and make this CC agnostic (except that >> I couldn't find the right spot for SEV-ES to clear that flag.) > > Maybe in sme_sev_setup_real_mode() in arch/x86/realmode/init.c? You could > clear the flag within the CC_ATTR_GUEST_STATE_ENCRYPT check. Eeew. Can we please have a AMD SEV-ES init specific place and not hijack some random code which has to check CC_ATTR_GUEST_STATE_ENCRYPT? Thanks, tglx
On 5/30/23 15:39, Thomas Gleixner wrote: > On Tue, May 30 2023 at 15:03, Tom Lendacky wrote: >> On 5/30/23 14:51, Thomas Gleixner wrote: >>> That aside. From a semantical POV making this decision about parallel >>> bootup based on some magic CC encryption attribute is questionable. >>> >>> I'm tending to just do the below and make this CC agnostic (except that >>> I couldn't find the right spot for SEV-ES to clear that flag.) >> >> Maybe in sme_sev_setup_real_mode() in arch/x86/realmode/init.c? You could >> clear the flag within the CC_ATTR_GUEST_STATE_ENCRYPT check. > > Eeew. > > Can we please have a AMD SEV-ES init specific place and not hijack some > random code which has to check CC_ATTR_GUEST_STATE_ENCRYPT? As long as it's not too early, you could try sme_early_init() in arch/x86/mm/mem_encrypt_amd.c. Add a check for sev_status & MSR_AMD64_SEV_ES_ENABLED and clear the flag. Thanks, Tom > > Thanks, > > tglx
--- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -1282,7 +1282,7 @@ bool __init arch_cpuhp_init_parallel_bri * Intel-TDX has a secure RDMSR hypercall, but that needs to be * implemented seperately in the low level startup ASM code. */ - if (cc_platform_has(CC_ATTR_GUEST_STATE_ENCRYPT)) { + if (cc_get_vendor() != CC_VENDOR_NONE) { pr_info("Parallel CPU startup disabled due to guest state encryption\n"); return false; }
The decision to allow parallel bringup of secondary CPUs checks CC_ATTR_GUEST_STATE_ENCRYPT to detect encrypted guests. Those cannot use parallel bootup because accessing the local APIC is intercepted and raises a #VC or #VE, which cannot be handled at that point. The check works correctly, but only for AMD encrypted guests. TDX does not set that flag. Check for cc_vendor != CC_VENDOR_NONE instead. That might be overbroad, but definitely works for both AMD and Intel. Fixes: 0c7ffa32dbd6 ("x86/smpboot/64: Implement arch_cpuhp_init_parallel_bringup() and enable it") Reported-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> --- arch/x86/kernel/smpboot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)