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 <teddy.astie@vates.tech>
---
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 */
/*
--
2.52.0
--
Teddy Astie | Vates XCP-ng Developer
XCP-ng & Xen Orchestra - Vates solutions
web: https://vates.tech
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 <teddy.astie@vates.tech>
> ---
> 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 <teddy.astie@vates.tech>
---
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
On Thu, Jan 08, 2026 at 04:50:51PM +0000, Teddy Astie wrote: > 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. Possibly a stupid question, but how is this information expected to be propagated to the guest when there's a guest firmware and bootloader in use? How is OVMF and/or grub propagating this information between themselves and to Linux? Are they relying on the CPUID discovery logic mentioned above, or there's some shadow infra used by KVM for example to already convey it? Adding Xen side-channels when there's an architectural defined way to obtain the information is a duplication of interfaces, and could lead to issues in the long run. We can not possibly be adding all vendor SEV options to SIF_ flags just because they are cumbersome to fetch. I know this is just one right now, but we don't know whether more of those CPUID options would be needed at the start of day in the future. > > ## 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. */ A concern I have with this is that we are adding vendor-specific terminology to what should otherwise be a vendor-agnostic interface. There's already a fair amount of arch-specific information encoded in there, so maybe not that much of a big deal. Thanks, Roger.
Le 08/01/2026 à 18:46, Roger Pau Monné a écrit : > On Thu, Jan 08, 2026 at 04:50:51PM +0000, Teddy Astie wrote: >> 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. > > Possibly a stupid question, but how is this information expected to > be propagated to the guest when there's a guest firmware and > bootloader in use? > > How is OVMF and/or grub propagating this information between > themselves and to Linux? > When booting Linux with SEV+UEFI, at least during the UEFI services, the UEFI firmware transparently handles #VC for the rest to allow it to perform CPUID operation. (with SEV-SNP CPUID page exposed with a specific UEFI mecanism) So overall, this proposal is only meaningful for PVH booting, everything that comes after can be handled differently. > Are they relying on the CPUID discovery logic mentioned above, or > there's some shadow infra used by KVM for example to already convey > it? > OVMF at its startup relies on #VC for emulating CPUID. It then relies on GHCB MSR for getting SEV info/C-bit (but only with SEV-ES). And under SEV-SNP, it uses "CPUID page" instead of GHCB (PAGE_TYPE_CPUID in SEV-SNP firmware ABI specification). This is because SEV/GHCB specification recommends using CPUID page under SEV-SNP (even though the same protocol as SEV-ES still works; but is discouraged). In GHCB Version 2 (SEV-SNP) > The hypervisor may supply the encryption bit position using the SEV Information MSR protocol, > but the guest should use the CPUID information supplied in the CPUID Page to determine the > encryption bit position. But its location is unfortunately undefined in this specification and in the OVMF case, hardcoded in firmware metadata. > Adding Xen side-channels when there's an architectural defined way to > obtain the information is a duplication of interfaces, and could lead > to issues in the long run. We can not possibly be adding all vendor > SEV options to SIF_ flags just because they are cumbersome to fetch. > I know this is just one right now, but we don't know whether more of > those CPUID options would be needed at the start of day in the future. > That exists for SEV-ES and SEV-SNP (even though complicated) but for SEV-SNP, it would relies on discouraged mecanisms (GHCB CPUID Request). AFAIU, this flag is enough for setting up long mode and GHCB which is what matters. There are some additional structures (e.g secret page and CPUID page) which could in the future be eventually exposed as PVH modules; which would be hopefully less intrusive. -- Some specialized boot process for SEV-SNP (e.g the one used COCONUT-SVSM) relies on IGVM [1] with custom memory layouts, initial pagetables, and so on. [1] https://github.com/microsoft/igvm >>> ## 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. */ > > A concern I have with this is that we are adding vendor-specific > terminology to what should otherwise be a vendor-agnostic interface. > > There's already a fair amount of arch-specific information encoded in > there, so maybe not that much of a big deal. > > Thanks, Roger. > -- Teddy Astie | Vates XCP-ng Developer XCP-ng & Xen Orchestra - Vates solutions web: https://vates.tech
On Thu, Jan 08, 2026 at 07:12:48PM +0000, Teddy Astie wrote: > Le 08/01/2026 à 18:46, Roger Pau Monné a écrit : > > On Thu, Jan 08, 2026 at 04:50:51PM +0000, Teddy Astie wrote: > >> 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. > > > > Possibly a stupid question, but how is this information expected to > > be propagated to the guest when there's a guest firmware and > > bootloader in use? > > > > How is OVMF and/or grub propagating this information between > > themselves and to Linux? > > > > When booting Linux with SEV+UEFI, at least during the UEFI services, the > UEFI firmware transparently handles #VC for the rest to allow it to > perform CPUID operation. > (with SEV-SNP CPUID page exposed with a specific UEFI mecanism) Hm, that's going to be cumbersome when using hvmloader in this scenario, as it makes extensive use of CPUID and hence would need to setup it's own #VC handler ahead of making use of CPUID. Or we must instead get rid of hvmloader. > So overall, this proposal is only meaningful for PVH booting, everything > that comes after can be handled differently. > > > Are they relying on the CPUID discovery logic mentioned above, or > > there's some shadow infra used by KVM for example to already convey > > it? > > > > OVMF at its startup relies on #VC for emulating CPUID. > It then relies on GHCB MSR for getting SEV info/C-bit (but only with > SEV-ES). And under SEV-SNP, it uses "CPUID page" instead of GHCB > (PAGE_TYPE_CPUID in SEV-SNP firmware ABI specification). > > This is because SEV/GHCB specification recommends using CPUID page under > SEV-SNP (even though the same protocol as SEV-ES still works; but is > discouraged). In a previous reply to Jan you mention that Linux already has such handlers, but just for the decompressing code (and hence not reachable from the PVH entry point, that's already decompressed code). Would it be possible to share the handlers with the PVH entry point? > In GHCB Version 2 (SEV-SNP) > > The hypervisor may supply the encryption bit position using the SEV Information MSR protocol, > > but the guest should use the CPUID information supplied in the CPUID Page to determine the > > encryption bit position. > > But its location is unfortunately undefined in this specification and in > the OVMF case, hardcoded in firmware metadata. > > > Adding Xen side-channels when there's an architectural defined way to > > obtain the information is a duplication of interfaces, and could lead > > to issues in the long run. We can not possibly be adding all vendor > > SEV options to SIF_ flags just because they are cumbersome to fetch. > > I know this is just one right now, but we don't know whether more of > > those CPUID options would be needed at the start of day in the future. > > > > That exists for SEV-ES and SEV-SNP (even though complicated) but for > SEV-SNP, it would relies on discouraged mecanisms (GHCB CPUID Request). > > AFAIU, this flag is enough for setting up long mode and GHCB which is > what matters. There are some additional structures (e.g secret page and > CPUID page) which could in the future be eventually exposed as PVH > modules; which would be hopefully less intrusive. If my understating is correct, this is not needed for the initial implementation of SEV (when hypervisor doesn't implement ES or SNP guests can use CPUID), and hence it might be best to wait for the basic SEV implementation to be in the hypervisor before jumping into ES or SNP details? AFAICT (from your Linux entry point patch) you end up needing both the CPUID and the GHCB ways of detecting SEV support, so one doesn't preclude the other. > -- > > Some specialized boot process for SEV-SNP (e.g the one used > COCONUT-SVSM) relies on IGVM [1] with custom memory layouts, initial > pagetables, and so on. > > [1] https://github.com/microsoft/igvm > > >>> ## 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. */ > > > > A concern I have with this is that we are adding vendor-specific > > terminology to what should otherwise be a vendor-agnostic interface. > > > > There's already a fair amount of arch-specific information encoded in > > there, so maybe not that much of a big deal. If we end up getting this bit, I think it needs to be clear it's a vendor specific feature: SIF_AMD_SEV_GHCB or similar would be better IMO. Thanks, Roger.
Le 09/01/2026 à 09:59, Roger Pau Monné a écrit : > On Thu, Jan 08, 2026 at 07:12:48PM +0000, Teddy Astie wrote: >> Le 08/01/2026 à 18:46, Roger Pau Monné a écrit : >>> On Thu, Jan 08, 2026 at 04:50:51PM +0000, Teddy Astie wrote: >>>> 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. >>> >>> Possibly a stupid question, but how is this information expected to >>> be propagated to the guest when there's a guest firmware and >>> bootloader in use? >>> >>> How is OVMF and/or grub propagating this information between >>> themselves and to Linux? >>> >> >> When booting Linux with SEV+UEFI, at least during the UEFI services, the >> UEFI firmware transparently handles #VC for the rest to allow it to >> perform CPUID operation. >> (with SEV-SNP CPUID page exposed with a specific UEFI mecanism) > > Hm, that's going to be cumbersome when using hvmloader in this > scenario, as it makes extensive use of CPUID and hence would need to > setup it's own #VC handler ahead of making use of CPUID. > > Or we must instead get rid of hvmloader. > For plain SEV, hvmloader would need to run with paging (PAE or 4-level) to properly handle encryption bit. But would also need Xen to handle MMIO instructions (which has some quirks due to being in encrypted memory). For SEV-ES, #VC handler + GHCB is not only required for CPUID, but also for VMMCALL, MMIO, some MSR accesses, ... It would be easier to not use hvmloader, especially since only UEFI supports SEV and guests would still need to support (Xen-specific) SEV bits to begin with. >> So overall, this proposal is only meaningful for PVH booting, everything >> that comes after can be handled differently. >> >>> Are they relying on the CPUID discovery logic mentioned above, or >>> there's some shadow infra used by KVM for example to already convey >>> it? >>> >> >> OVMF at its startup relies on #VC for emulating CPUID. >> It then relies on GHCB MSR for getting SEV info/C-bit (but only with >> SEV-ES). And under SEV-SNP, it uses "CPUID page" instead of GHCB >> (PAGE_TYPE_CPUID in SEV-SNP firmware ABI specification). >> >> This is because SEV/GHCB specification recommends using CPUID page under >> SEV-SNP (even though the same protocol as SEV-ES still works; but is >> discouraged). > > In a previous reply to Jan you mention that Linux already has such > handlers, but just for the decompressing code (and hence not reachable > from the PVH entry point, that's already decompressed code). Would it > be possible to share the handlers with the PVH entry point? > Maybe, Linux already does this for few parts of SEV code (e.g arch/x86/coco/sev/vc-shared.c being also included in arch/x86/boot/compressed/sev-handle-vc.c). Everything we would need appears to be contained in arch/x86/boot/compressed/mem_encrypt.S. >> In GHCB Version 2 (SEV-SNP) >>> The hypervisor may supply the encryption bit position using the SEV Information MSR protocol, >>> but the guest should use the CPUID information supplied in the CPUID Page to determine the >>> encryption bit position. >> >> But its location is unfortunately undefined in this specification and in >> the OVMF case, hardcoded in firmware metadata. >> >>> Adding Xen side-channels when there's an architectural defined way to >>> obtain the information is a duplication of interfaces, and could lead >>> to issues in the long run. We can not possibly be adding all vendor >>> SEV options to SIF_ flags just because they are cumbersome to fetch. >>> I know this is just one right now, but we don't know whether more of >>> those CPUID options would be needed at the start of day in the future. >>> >> >> That exists for SEV-ES and SEV-SNP (even though complicated) but for >> SEV-SNP, it would relies on discouraged mecanisms (GHCB CPUID Request). >> >> AFAIU, this flag is enough for setting up long mode and GHCB which is >> what matters. There are some additional structures (e.g secret page and >> CPUID page) which could in the future be eventually exposed as PVH >> modules; which would be hopefully less intrusive. > > If my understating is correct, this is not needed for the initial > implementation of SEV (when hypervisor doesn't implement ES or SNP > guests can use CPUID), and hence it might be best to wait for the > basic SEV implementation to be in the hypervisor before jumping into > ES or SNP details? > Correct; CPUID is handled normally when not running with SEV-ES/SNP. > AFAICT (from your Linux entry point patch) you end up needing both the > CPUID and the GHCB ways of detecting SEV support, so one doesn't > preclude the other. > Both are needed if we want to support both SEV-ES and no-ES cases; but if only SEV-ES+ is wanted, the CPUID path would never be taken with this approach. >> -- >> >> Some specialized boot process for SEV-SNP (e.g the one used >> COCONUT-SVSM) relies on IGVM [1] with custom memory layouts, initial >> pagetables, and so on. >> >> [1] https://github.com/microsoft/igvm >> >>>>> ## 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. */ >>> >>> A concern I have with this is that we are adding vendor-specific >>> terminology to what should otherwise be a vendor-agnostic interface. >>> >>> There's already a fair amount of arch-specific information encoded in >>> there, so maybe not that much of a big deal. > > If we end up getting this bit, I think it needs to be clear it's a > vendor specific feature: SIF_AMD_SEV_GHCB or similar would be better > IMO. > I was thinking in case another vendor (non-AMD) implements this interface, but the MSR already has AMD_SEV in its name; so I'm ok using something like SIF_AMD_SEV_GHCB. > Thanks, Roger. > -- Teddy Astie | Vates XCP-ng Developer XCP-ng & Xen Orchestra - Vates solutions web: https://vates.tech
On Fri, Jan 09, 2026 at 10:31:57AM +0000, Teddy Astie wrote: > Le 09/01/2026 à 09:59, Roger Pau Monné a écrit : > > On Thu, Jan 08, 2026 at 07:12:48PM +0000, Teddy Astie wrote: > >> Le 08/01/2026 à 18:46, Roger Pau Monné a écrit : > >>> On Thu, Jan 08, 2026 at 04:50:51PM +0000, Teddy Astie wrote: > >>>> 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. > >>> > >>> Possibly a stupid question, but how is this information expected to > >>> be propagated to the guest when there's a guest firmware and > >>> bootloader in use? > >>> > >>> How is OVMF and/or grub propagating this information between > >>> themselves and to Linux? > >>> > >> > >> When booting Linux with SEV+UEFI, at least during the UEFI services, the > >> UEFI firmware transparently handles #VC for the rest to allow it to > >> perform CPUID operation. > >> (with SEV-SNP CPUID page exposed with a specific UEFI mecanism) > > > > Hm, that's going to be cumbersome when using hvmloader in this > > scenario, as it makes extensive use of CPUID and hence would need to > > setup it's own #VC handler ahead of making use of CPUID. > > > > Or we must instead get rid of hvmloader. > > > > For plain SEV, hvmloader would need to run with paging (PAE or 4-level) > to properly handle encryption bit. But would also need Xen to handle > MMIO instructions (which has some quirks due to being in encrypted memory). Does hvmloader really need encryption though? What sensitive data does hvmloader deal with that would require encryption. > For SEV-ES, #VC handler + GHCB is not only required for CPUID, but also > for VMMCALL, MMIO, some MSR accesses, ... > > It would be easier to not use hvmloader, especially since only UEFI > supports SEV and guests would still need to support (Xen-specific) SEV > bits to begin with. I would be very happy to relegate hvmloader to be used with SeaBIOS only, and to load OVMF directly for HVM guests. But I don't know what's missing for OVMF to be capable of that. I would think not much, since it's already almost working for PVH guests AFAIK. Maybe PCI enumeration, but OVMF must have a way of doing that already for other platforms I expect. > >> So overall, this proposal is only meaningful for PVH booting, everything > >> that comes after can be handled differently. > >> > >>> Are they relying on the CPUID discovery logic mentioned above, or > >>> there's some shadow infra used by KVM for example to already convey > >>> it? > >>> > >> > >> OVMF at its startup relies on #VC for emulating CPUID. > >> It then relies on GHCB MSR for getting SEV info/C-bit (but only with > >> SEV-ES). And under SEV-SNP, it uses "CPUID page" instead of GHCB > >> (PAGE_TYPE_CPUID in SEV-SNP firmware ABI specification). > >> > >> This is because SEV/GHCB specification recommends using CPUID page under > >> SEV-SNP (even though the same protocol as SEV-ES still works; but is > >> discouraged). > > > > In a previous reply to Jan you mention that Linux already has such > > handlers, but just for the decompressing code (and hence not reachable > > from the PVH entry point, that's already decompressed code). Would it > > be possible to share the handlers with the PVH entry point? > > > > Maybe, Linux already does this for few parts of SEV code (e.g > arch/x86/coco/sev/vc-shared.c being also included in > arch/x86/boot/compressed/sev-handle-vc.c). > > Everything we would need appears to be contained in > arch/x86/boot/compressed/mem_encrypt.S. I don't know that much about Linux whether it would be easy for the PVH entry point to re-use that code. > >> In GHCB Version 2 (SEV-SNP) > >>> The hypervisor may supply the encryption bit position using the SEV Information MSR protocol, > >>> but the guest should use the CPUID information supplied in the CPUID Page to determine the > >>> encryption bit position. > >> > >> But its location is unfortunately undefined in this specification and in > >> the OVMF case, hardcoded in firmware metadata. > >> > >>> Adding Xen side-channels when there's an architectural defined way to > >>> obtain the information is a duplication of interfaces, and could lead > >>> to issues in the long run. We can not possibly be adding all vendor > >>> SEV options to SIF_ flags just because they are cumbersome to fetch. > >>> I know this is just one right now, but we don't know whether more of > >>> those CPUID options would be needed at the start of day in the future. > >>> > >> > >> That exists for SEV-ES and SEV-SNP (even though complicated) but for > >> SEV-SNP, it would relies on discouraged mecanisms (GHCB CPUID Request). > >> > >> AFAIU, this flag is enough for setting up long mode and GHCB which is > >> what matters. There are some additional structures (e.g secret page and > >> CPUID page) which could in the future be eventually exposed as PVH > >> modules; which would be hopefully less intrusive. > > > > If my understating is correct, this is not needed for the initial > > implementation of SEV (when hypervisor doesn't implement ES or SNP > > guests can use CPUID), and hence it might be best to wait for the > > basic SEV implementation to be in the hypervisor before jumping into > > ES or SNP details? > > > > Correct; CPUID is handled normally when not running with SEV-ES/SNP. > > > AFAICT (from your Linux entry point patch) you end up needing both the > > CPUID and the GHCB ways of detecting SEV support, so one doesn't > > preclude the other. > > > > Both are needed if we want to support both SEV-ES and no-ES cases; but > if only SEV-ES+ is wanted, the CPUID path would never be taken with this > approach. Since in Xen we do want to support plain SEV (without ES extensions), I would focus initially on the CPUID path, because it would be needed anyway. Get that working on both Xen and Linux, and then discuss about any ES/SNP ABI additions. It seems premature to do ABI changes to accommodate ES/SNP support when not even plain SEV is supported. Thanks, Roger.
On Fri, Jan 09, 2026 at 12:37:30PM +0100, Roger Pau Monné wrote: > On Fri, Jan 09, 2026 at 10:31:57AM +0000, Teddy Astie wrote: > > It would be easier to not use hvmloader, especially since only UEFI > > supports SEV and guests would still need to support (Xen-specific) SEV > > bits to begin with. > > I would be very happy to relegate hvmloader to be used with SeaBIOS > only, and to load OVMF directly for HVM guests. But I don't know > what's missing for OVMF to be capable of that. I would think not > much, since it's already almost working for PVH guests AFAIK. OvmfXen works in PVH, and you can start guest ;-), the last change was to remove the use of the hypercall page so the shutdown hypercall could be called from UEFI Runtime Service. > Maybe PCI enumeration, but OVMF must have a way of doing that already > for other platforms I expect. Yes, that would probably be the main thing, I believe. It might just be a setting to enable enumeration when OvmfXen is started via the PVH entry point, I haven't really try to boot OVMF in HVM without hvmloader yet, and we would need to change the tool stack to boot an HVM guest via the PVH entry point. But, I already have a prototype of OvmfXen that could boot (modified) Linux in an SEV guest, it's based on SEV work from sometime ago so might not work anymore (and I don't remember if linux could start userspace): https://xenbits.xenproject.org/gitweb/?p=people/aperard/ovmf.git;a=log;h=refs/heads/wip.sev Cheers, -- Anthony PERARD
On 28.12.2025 13:49, Teddy Astie wrote: > 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. But isn't this going to be needed for plain HVM anyway? > --- 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. */ Naming-wise, do we really want to tie this to AMD (and hence exclude other vendors, or require yet another bit to be allocated later)? Jan
Le 29/12/2025 à 09:24, Jan Beulich a écrit : > On 28.12.2025 13:49, Teddy Astie wrote: >> 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. > > But isn't this going to be needed for plain HVM anyway? > This hint is only relevant for PVH entry point. The other guest boot paths can still rely on other mechanisms, e.g UEFI boot doesn't rely on the IDT approach and relies instead on the UEFI firmware to provide the early GHCB handler for the OS. From a Linux implementation standpoint, as PVH entry-point doesn't live in compressed/ boot code of Linux, the early-GHCB handlers (do_vc_no_ghcb and do_boot_stage2_vc) don't exist from there; so we either need to reimplement in non-compressed code or use another approach. >> --- 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. */ > > Naming-wise, do we really want to tie this to AMD (and hence exclude other > vendors, or require yet another bit to be allocated later)? > This is SEV-ES/SNP only, I don't think the same bit can be reused for another technology (unless it also uses the GHCB MSR). As the guest can't even check if it is Intel or AMD CPU at this point (if running under SEV-ES or SEV-SNP). > Jan > Teddy -- Teddy Astie | Vates XCP-ng Developer XCP-ng & Xen Orchestra - Vates solutions web: https://vates.tech
On 29.12.2025 13:39, Teddy Astie wrote: > Le 29/12/2025 à 09:24, Jan Beulich a écrit : >> On 28.12.2025 13:49, Teddy Astie wrote: >>> --- 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. */ >> >> Naming-wise, do we really want to tie this to AMD (and hence exclude other >> vendors, or require yet another bit to be allocated later)? > > This is SEV-ES/SNP only, I don't think the same bit can be reused for > another technology (unless it also uses the GHCB MSR). As the guest > can't even check if it is Intel or AMD CPU at this point (if running > under SEV-ES or SEV-SNP). If it was just telling AMD from Intel, that would be possible. There are a few well-known differences in how certain instructions behave [1]. But here you aren't after telling apart the vendors; you want to know whether you're (fundamentally) on SVM or VT-x. Of course I have to admit that I find it quite irritating that in order to execute CPUID one has to have a #VC handler properly set up. This inverses the typical flow of events. Did they really not think of some replacement for at least the most basic information? Jan [1] Of course, such details can change going forward. Vendors did alter the behavior of certain insns in the past.
Le 29/12/2025 à 15:16, Jan Beulich a écrit : > On 29.12.2025 13:39, Teddy Astie wrote: >> Le 29/12/2025 à 09:24, Jan Beulich a écrit : >>> On 28.12.2025 13:49, Teddy Astie wrote: >>>> --- 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. */ >>> >>> Naming-wise, do we really want to tie this to AMD (and hence exclude other >>> vendors, or require yet another bit to be allocated later)? >> >> This is SEV-ES/SNP only, I don't think the same bit can be reused for >> another technology (unless it also uses the GHCB MSR). As the guest >> can't even check if it is Intel or AMD CPU at this point (if running >> under SEV-ES or SEV-SNP). > > If it was just telling AMD from Intel, that would be possible. There are > a few well-known differences in how certain instructions behave [1]. But > here you aren't after telling apart the vendors; you want to know whether > you're (fundamentally) on SVM or VT-x. > > Of course I have to admit that I find it quite irritating that in order > to execute CPUID one has to have a #VC handler properly set up. This > inverses the typical flow of events. Did they really not think of some > replacement for at least the most basic information? > Yes, but only with more information beforehand. Regarding the #VC approach, the negociation example also state this > The above example is just one way to perform the GHCB negotiation for an SEV-ES guest. For example, you could use the GHCBInfo = 0x004 CPUID Request to obtain actual values for the CPUID instructions executed by the guest. Or you could use the GHCBInfo = 0x002 Request for SEV Information if MSR 0xc001_0130 does not contain the GHCBInfo = 0x001 SEV Information. But that only works as long as you know GHCB MSR is available; which you may be able to check through SEV_STATUS MSR; but this MSR is only meaningful on CPUs that supports SEV (APM says the hypervisor cannot intercept these MSRs). This proposal aims to give this information to the guest through the start_info structure. Under SEV-ES/SNP, the hypervisor cannot fake EFER MSR which in this case may have forced guest-visible EFER:SVME, it could be a way to check for SEV-ES for but it's quite hacky and fragile. (I still need to test this though) > Jan > > [1] Of course, such details can change going forward. Vendors did alter > the behavior of certain insns in the past. > -- Teddy Astie | Vates XCP-ng Developer XCP-ng & Xen Orchestra - Vates solutions web: https://vates.tech
© 2016 - 2026 Red Hat, Inc.