Le 28/12/2025 à 13:54, Teddy Astie a écrit : > Under SEV, the pagetables needs to be post-processed to add the C-bit > (to make the mapping encrypted). The guest is expected to query the C-bit > through CPUID. However, under SEV-ES and SEV-SNP modes, this instruction > now triggers #VC instead. The guest would need to setup a IDT very early > and instead use the early-GHCB protocol to emulate CPUID, which is > complicated. > > Alternatively, we can signal to the guest that it is a SEV-ES/SNP through > start_info structure, which is visible to the guest early on. All SEV-ES/SNP > guests have the GHCB MSR available, which can be trivially [1] used to get the > C-bit and proceed with the initialization avoiding CPUID instruction. > > We integrate that to the PVH ABI and expect all SEV-enabled domain builders > to honor this flag for simplifying the PVH entry point logic of guests. > > [1] Initial GHCB MSR value contains the C-bit. The guest can trivially read > this > MSR and skip CPUID logic. > > Signed-off-by: Teddy Astie <[email protected]> > --- > Actually, C-bit itself cannot be a part of ABI as it is hardware-dependant > (and even firmware configuration dependant). > --- > docs/misc/pvh.pandoc | 5 +++++ > xen/include/public/xen.h | 2 ++ > 2 files changed, 7 insertions(+) > > diff --git a/docs/misc/pvh.pandoc b/docs/misc/pvh.pandoc > index 3e18789d36..6453ee21eb 100644 > --- a/docs/misc/pvh.pandoc > +++ b/docs/misc/pvh.pandoc > @@ -44,6 +44,11 @@ using HVMPARAMS, just like it's done on HVM guests. > The setup of the hypercall page is also performed in the same way > as HVM guests, using the hypervisor cpuid leaves and msr ranges. > > +## SEV-ES/SNP guests ## > + > +The domain builder must set `SIF_HVM_GHCB` in start_info if the guest uses > +SEV-ES or SEV-SNP technologies; i.e requires the use of GHCB protocol. > + > ## AP startup ## > > AP startup can be performed using hypercalls or the local APIC if present. > diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h > index 7f15204c38..9b84df573b 100644 > --- a/xen/include/public/xen.h > +++ b/xen/include/public/xen.h > @@ -890,6 +890,8 @@ typedef struct start_info start_info_t; > #define SIF_MOD_START_PFN (1<<3) /* Is mod_start a PFN? */ > #define SIF_VIRT_P2M_4TOOLS (1<<4) /* Do Xen tools understand a virt. > mapped */ > /* P->M making the 3 level tree > obsolete? */ > +#define SIF_HVM_GHCB (1<<5) /* Domain is SEV-ES/SNP guest that > requires */ > + /* use of GHCB. */ > #define SIF_PM_MASK (0xFF<<8) /* reserve 1 byte for xen-pm options */ > > /*
As requested, here is how it could be used for Linux (the patch also contains plain SEV support). We check here for SEV-ES with mov 8(%ebx), %edx (start_info->flags) bt $5, %edx (SIF_HVM_GHCB) If checked, we then read GHCB MSR and extract C-bit from it and skip the CPUID checks. --- Subject: [RFC PATCH] pvh: Add SEV/SEV-ES support for PVH boot When running as a SEV guest with PVH entrypoint, we need to fixup the page tables to add the C-bit. Otherwise, the transition to long mode fails as the pagetables are invalid under SEV. Signed-off-by: Teddy Astie <[email protected]> --- arch/x86/platform/pvh/head.S | 74 ++++++++++++++++++++++++++++++++++++ include/xen/interface/xen.h | 2 + 2 files changed, 76 insertions(+) diff --git a/arch/x86/platform/pvh/head.S b/arch/x86/platform/pvh/head.S index 1d78e5631bb8..2b4d58350346 100644 --- a/arch/x86/platform/pvh/head.S +++ b/arch/x86/platform/pvh/head.S @@ -91,6 +91,64 @@ SYM_CODE_START(pvh_start_xen) leal rva(early_stack_end)(%ebp), %esp +#ifdef CONFIG_AMD_MEM_ENCRYPT + /* Check SIF_HVM_GHCB flag in start_info informing us on SEV-ES/SNP */ + mov 8(%ebx), %edx + bt $5, %edx + jnc .no_ghcb + + /* Get C-bit through GHCB MSR. */ + movl $MSR_AMD64_SEV_ES_GHCB, %ecx + rdmsr + /* C-bit is in EAX[31:24] */ + shr $24, %eax + mov %eax, %ebx + jmp .sev_prepare_pgt + +.no_ghcb: + /* Check CPUID highest leaf */ + mov $0x80000000, %eax + cpuid + cmp $0x8000001f, %eax + jb .skip_sev_prepare_pgt + + /* Check for SEV support */ + mov $0x8000001f, %eax + cpuid + bt $1, %eax + jnc .skip_sev_prepare_pgt + +.sev_prepare_pgt: + /* Check if SEV is enabled */ + mov $MSR_AMD64_SEV, %ecx + rdmsr + bt $MSR_AMD64_SEV_ENABLED_BIT, %eax + jnc .skip_sev_prepare_pgt + + mov %ebx, %ecx + and $0x3f, %ecx /* Get C-bit position */ + sub $0x20, %ecx + mov $1, %eax + shl %cl, %eax + + leal rva(pvh_init_top_pgt)(%ebp), %esi + call set_pgtable_cbit + + leal rva(pvh_level3_ident_pgt)(%ebp), %esi + call set_pgtable_cbit + + leal rva(pvh_level3_kernel_pgt)(%ebp), %esi + call set_pgtable_cbit + + leal rva(pvh_level2_ident_pgt)(%ebp), %esi + call set_pgtable_cbit + + leal rva(pvh_level2_kernel_pgt)(%ebp), %esi + call set_pgtable_cbit + +.skip_sev_prepare_pgt: +#endif + /* Enable PAE mode. */ mov %cr4, %eax orl $X86_CR4_PAE, %eax @@ -223,6 +281,22 @@ SYM_CODE_START(pvh_start_xen) #endif SYM_CODE_END(pvh_start_xen) +#ifdef CONFIG_AMD_MEM_ENCRYPT +SYM_FUNC_START_LOCAL(set_pgtable_cbit) + .code32 + mov $512, %ecx + xor %edx, %edx +.L2: + testl $_PAGE_PRESENT, 0(%esi,%edx,8) + jz .L3 + or %eax, 4(%esi,%edx,8) +.L3: + inc %edx + loop .L2 + RET +SYM_FUNC_END(set_pgtable_cbit) +#endif + .section ".init.data","aw" .balign 8 SYM_DATA_START_LOCAL(gdt) diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h index 0ca23eca2a9c..c1a4e3dca0a3 100644 --- a/include/xen/interface/xen.h +++ b/include/xen/interface/xen.h @@ -654,6 +654,8 @@ struct start_info { #define SIF_MOD_START_PFN (1<<3) /* Is mod_start a PFN? */ #define SIF_VIRT_P2M_4TOOLS (1<<4) /* Do Xen tools understand a virt. mapped */ /* P->M making the 3 level tree obsolete? */ +#define SIF_HVM_GHCB (1<<5) /* Domain is SEV-ES/SNP guest so require */ + /* use of GHCB protocol. */ #define SIF_PM_MASK (0xFF<<8) /* reserve 1 byte for xen-pm options */ /* -- 2.52.0 -- Teddy Astie | Vates XCP-ng Developer XCP-ng & Xen Orchestra - Vates solutions web: https://vates.tech
