Alternate Injection: Secure Interrupt Delivery for SEV-SNP Guests - Guest Support
Subsystems (3)
v2 cover Alternate Injection: Secure Interrupt Delivery for SEV-SNP Guests - Guest Support
Hi all,
This revision fixes all the review comments from version 1.
The changes include:
1. Changed a few comments for better understanding, deleted some unnecessary code, corrected some typos, and some minor code fixes from the review comments by Sashiko and Boris.
2. Unified sev_apic_ghcb_msr_write() and sev_apic_ghcb_msr_read().
3. Move x2apic_svsm.o after x2apic_savic.o so that the secure AVIC gets preferred on machines supporting it.
4. Reworked svsm_apic_probe() as Boris suggested.
5. Updated tools with renamed MSR_AMD64_SNP_ALTERNATE_INJ_BIT and MSR_AMD64_SNP_ALT_INJ for completeness' sake.
6. Changed svsm_apic_send_IPI_self() with writing to the dedicated APIC_SELF_IPI instead of writing to APIC_ICR.
Thanks,
Melody
Changelog:
v1
--
The revision fixes all of the review comments from version 0.
The changes include:
1. Changed a few commit messages, new file names, variables name and order, function names and more comments for better understanding.
2. Added a pre-patch to fix the problem that in two functions in the the SVSM vTPM guest implementation do not disable preemption when fetching CAA. It is moving the CAA fetching operation inside svsm_perform_call_protocol().
This series relies on this fix too.
3. Removed svsm_do_call() helper function and some intermediary layer functions in SVSM APIC driver.
4. Removed the Secure AVIC check in SVSM APIC driver since it will never be touched.
5. Terminate boot when Alternate Injection is enabled in vmpl0.
6. Added a common function for SVSM APIC read and write.
7. Added a new SEV_TERM_SET_LINUX value for Alternate Injection and APIC ghcb msr read/write.
8. Reworked sev_prepare() to reflect the error conditions correctly.
9. Moved allowing all of interrupts right after registering the SVSM APIC protocol.
v0
--
Alternate Injection is a method to provide secure interrupt delivery for SEV-SNP guests against malicious injection attacks. By handing over the control of the interrupt injection to the guest itself, the security is applied. Alternate Injection use Secure VM Service Module (SVSM), and APIC emulation in the SVSM to secure interrupt delivery.
This is the guest side patches. The patch set includes the following:
1. Add support for enabling Alternate Injection.
2. Add support for the SVSM APIC protocol which uses a subset of the X2APIC MSRs.
3. Add support to allow the guest OS to request Alternate Injection.
Melody Wang (8):
x86/sev: Make SVSM calls preemption-safe
x86/sev: Add support for Alternate Injection
x86/apic: Add an SVSM APIC driver
x86/sev: Route unsupported APIC register accesses to the hypervisor
APIC emulation
x86/sev: Add a function to contain all SEV-specific setup operations x86/sev: Register the guest with the SVSM APIC protocol x86/sev: Allow the guest to configure interrupt vectors for the
hypervisor
x86/sev: Indicate that Alternate Injection is supported in the guest
arch/x86/Kconfig | 14 ++ arch/x86/boot/compressed/sev.c | 50 ++++- arch/x86/boot/compressed/sev.h | 13 ++ arch/x86/coco/core.c | 3 + arch/x86/coco/sev/core.c | 48 ++--- arch/x86/coco/sev/svsm.c | 10 +- arch/x86/include/asm/msr-index.h | 4 +- arch/x86/include/asm/sev-common.h | 2 + arch/x86/include/asm/sev.h | 20 +- arch/x86/kernel/apic/Makefile | 1 + arch/x86/kernel/apic/x2apic_savic.c | 8 +- arch/x86/kernel/apic/x2apic_svsm.c | 243 ++++++++++++++++++++++++ drivers/firmware/efi/libstub/x86-stub.c | 17 +- include/linux/cc_platform.h | 8 + tools/arch/x86/include/asm/msr-index.h | 4 +- 15 files changed, 385 insertions(+), 60 deletions(-) create mode 100644 arch/x86/kernel/apic/x2apic_svsm.c
Signature · 1 line
2.43.0
PATCH v2 1/8 x86/sev: Make SVSM calls preemption-safe
Two functions in the the SVSM vTPM guest implementation do not disable preemption when fetching the SVSM Calling Area Address (CAA).
The SVSM CAA is a per-CPU structure. When a thread is preempted and migrated to a different CPU after fetching the per-CPU CAA, the SVSM call will execute on the new CPU with the original CPU's CAA. Which is wrong.
Move the CAA fetching operation inside svsm_perform_call_protocol() which disables interrupts around the SVSM call and thus runs preemption-safe.
--- arch/x86/coco/sev/svsm.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
arch/x86/coco/sev/svsm.c +8 -2
@@ -74,6 +74,14 @@ int svsm_perform_call_protocol(struct svsm_call *call) flags =native_local_irq_save (); +/* +* 'caa' is a per-CPU variable. To avoid using a stale or incorrect +* 'caa' if the task is preempted or migrated to another CPU after it +* is fetched, always fetch 'caa' and then issue the SVSM call with +* interrupts disabled. This ensures the correct 'caa' is used. +*/ + call->caa =svsm_get_caa (); + ghcb =__sev_get_ghcb (&state); do {
@@ -321,7 +329,6 @@ int snp_svsm_vtpm_send_command(u8 *buffer) {struct svsm_call call = {}; - call.caa =svsm_get_caa (); call.rax =SVSM_VTPM_CALL (SVSM_VTPM_CMD ); call.rcx =__pa (buffer);
@@ -345,7 +352,6 @@ bool snp_svsm_vtpm_probe(void)if (!snp_vmpl)return false; - call.caa =svsm_get_caa (); call.rax =SVSM_VTPM_CALL (SVSM_VTPM_QUERY );if (svsm_perform_call_protocol (&call))
Signature · 1 line
2.43.0
[tip: x86/urgent] x86/sev: Make vTPM SVSM calls preemption-safe
The following commit has been merged into the x86/urgent branch of tip:
The following commit has been merged into the x86/urgent branch of tip:
Commit-ID: 6c43c72748fffd29dec15cd1f31e9a32949bc437 Gitweb: https://git.kernel.org/tip/6c43c72748fffd29dec15cd1f31e9a32949bc437 Author: Melody Wang <[email protected]> AuthorDate: Mon, 14 Sep 2026 00:57:17 Committer: Borislav Petkov (AMD) <[email protected]> CommitterDate: Mon, 21 Sep 2026 19:59:25 -07:00
x86/sev: Make vTPM SVSM calls preemption-safe
Two functions in the SVSM vTPM guest implementation do not disable preemption when fetching the SVSM Calling Area Address (CAA).
The SVSM CAA is a per-CPU structure. When a thread is preempted and migrated to a different CPU after fetching the per-CPU CAA, the SVSM call will execute on the new CPU with the original CPU's CAA. Which is wrong.
Move the CAA fetching operation inside svsm_perform_call_protocol() which disables interrupts around the SVSM call and thus runs preemption-safe.
--- arch/x86/coco/sev/svsm.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
arch/x86/coco/sev/svsm.c +8 -2
@@ -74,6 +74,14 @@ int svsm_perform_call_protocol(struct svsm_call *call) flags =native_local_irq_save (); +/* +* 'caa' is a per-CPU variable. To avoid using a stale or incorrect +* 'caa' if the task is preempted or migrated to another CPU after it +* is fetched, always fetch 'caa' and then issue the SVSM call with +* interrupts disabled. This ensures the correct 'caa' is used. +*/ + call->caa =svsm_get_caa (); + ghcb =__sev_get_ghcb (&state); do {
@@ -321,7 +329,6 @@ int snp_svsm_vtpm_send_command(u8 *buffer) {struct svsm_call call = {}; - call.caa =svsm_get_caa (); call.rax =SVSM_VTPM_CALL (SVSM_VTPM_CMD ); call.rcx =__pa (buffer);
@@ -345,7 +352,6 @@ bool snp_svsm_vtpm_probe(void)if (!snp_vmpl)return false; - call.caa =svsm_get_caa (); call.rax =SVSM_VTPM_CALL (SVSM_VTPM_QUERY );if (svsm_perform_call_protocol (&call))
PATCH v2 2/8 x86/sev: Add support for Alternate Injection
In reply to Melody WangThe Alternate Injection feature is a method to protect a SNP guest from malicious injection attacks. It allows the guest to control the interrupt injection.
When this feature is enabled, interrupts are injected with the help of an agent called a Secure VM Service Module (SVSM) which executes in the security realm of the guest and uses Restricted Injection as the sole method to receive interrupts from the hypervisor.
Add support for Alternate Injection.
--- arch/x86/Kconfig | 14 ++++++++++++++ arch/x86/boot/compressed/sev.c | 2 +- arch/x86/coco/core.c | 3 +++ arch/x86/coco/sev/core.c | 2 +- arch/x86/include/asm/msr-index.h | 4 ++-- include/linux/cc_platform.h | 8 ++++++++ tools/arch/x86/include/asm/msr-index.h | 4 ++-- 7 files changed, 31 insertions(+), 6 deletions(-)
arch/x86/Kconfig +14 -0
@@ -496,6 +496,20 @@ config AMD_SECURE_AVIC If you don't know what to do here, say N. +config AMD_ALTERNATE_INJ + bool "Support Alternate Injection" + depends on X86_X2APIC && AMD_MEM_ENCRYPT + help + Enable AMD Alternate Injection support for SNP guests. + + The Alternate Injection feature of SEV-SNP enhances the security of + a confidential VM by preventing the untrusted host from presenting + unexpected interrupts or exceptions, while still preserving the + standard interrupt dispatch semantics inherent to the x86 + architecture. + + If you don't know what to do here, say N. + config X86_POSTED_MSI bool "Enable MSI and MSI-x delivery by posted interrupts" depends on X86_64 && IRQ_REMAP
arch/x86/boot/compressed/sev.c +1 -1
@@ -179,7 +179,7 @@ bool sev_es_check_ghcb_fault(unsigned long address)#define SNP_FEATURES_IMPL_REQ (MSR_AMD64_SNP_VTOM | \ MSR_AMD64_SNP_REFLECT_VC | \ MSR_AMD64_SNP_RESTRICTED_INJ | \ - MSR_AMD64_SNP_ALT_INJ | \ + MSR_AMD64_SNP_ALTERNATE_INJ | \ MSR_AMD64_SNP_DEBUG_SWAP | \ MSR_AMD64_SNP_VMPL_SSS | \ MSR_AMD64_SNP_SECURE_TSC | \
arch/x86/coco/core.c +3 -0
@@ -107,6 +107,9 @@ static bool noinstr amd_cc_platform_has(enum cc_attr attr)case CC_ATTR_SNP_SECURE_AVIC :return sev_status &MSR_AMD64_SNP_SECURE_AVIC ; +case CC_ATTR_SNP_ALTERNATE_INJECTION : +return sev_status &MSR_AMD64_SNP_ALTERNATE_INJ ; +default :return false; }
arch/x86/coco/sev/core.c +1 -1
@@ -78,7 +78,7 @@ static const char * const sev_status_feat_names[] = { [MSR_AMD64_SNP_VTOM_BIT] = "vTom", [MSR_AMD64_SNP_REFLECT_VC_BIT] = "ReflectVC", [MSR_AMD64_SNP_RESTRICTED_INJ_BIT] = "RI", - [MSR_AMD64_SNP_ALT_INJ_BIT] = "AI", + [MSR_AMD64_SNP_ALTERNATE_INJ_BIT] = "AI", [MSR_AMD64_SNP_DEBUG_SWAP_BIT] = "DebugSwap", [MSR_AMD64_SNP_PREVENT_HOST_IBS_BIT] = "NoHostIBS", [MSR_AMD64_SNP_BTB_ISOLATION_BIT] = "BTBIsol",
arch/x86/include/asm/msr-index.h +2 -2
@@ -728,8 +728,8 @@#define MSR_AMD64_SNP_REFLECT_VC BIT_ULL(MSR_AMD64_SNP_REFLECT_VC_BIT)#define MSR_AMD64_SNP_RESTRICTED_INJ_BIT 5#define MSR_AMD64_SNP_RESTRICTED_INJ BIT_ULL(MSR_AMD64_SNP_RESTRICTED_INJ_BIT) -#define MSR_AMD64_SNP_ALT_INJ_BIT 6 -#define MSR_AMD64_SNP_ALT_INJ BIT_ULL(MSR_AMD64_SNP_ALT_INJ_BIT) +#define MSR_AMD64_SNP_ALTERNATE_INJ_BIT 6 +#define MSR_AMD64_SNP_ALTERNATE_INJ BIT_ULL(MSR_AMD64_SNP_ALTERNATE_INJ_BIT)#define MSR_AMD64_SNP_DEBUG_SWAP_BIT 7#define MSR_AMD64_SNP_DEBUG_SWAP BIT_ULL(MSR_AMD64_SNP_DEBUG_SWAP_BIT)#define MSR_AMD64_SNP_PREVENT_HOST_IBS_BIT 8
include/linux/cc_platform.h +8 -0
@@ -104,6 +104,14 @@ enum cc_attr {* to run SEV-SNP guests with full Secure AVIC capabilities. */ CC_ATTR_SNP_SECURE_AVIC , + +/** +* @CC_ATTR_SNP_ALTERNATE_INJECTION: AMD Alternate Injection enabled. +* +* A Secure VM Service Module (SVSM) has started the guest with +* Alternate Injection enabled. +*/ + CC_ATTR_SNP_ALTERNATE_INJECTION, };#ifdef CONFIG_ARCH_HAS_CC_PLATFORM
tools/arch/x86/include/asm/msr-index.h +2 -2
@@ -721,8 +721,8 @@#define MSR_AMD64_SNP_REFLECT_VC BIT_ULL(MSR_AMD64_SNP_REFLECT_VC_BIT)#define MSR_AMD64_SNP_RESTRICTED_INJ_BIT 5#define MSR_AMD64_SNP_RESTRICTED_INJ BIT_ULL(MSR_AMD64_SNP_RESTRICTED_INJ_BIT) -#define MSR_AMD64_SNP_ALT_INJ_BIT 6 -#define MSR_AMD64_SNP_ALT_INJ BIT_ULL(MSR_AMD64_SNP_ALT_INJ_BIT) +#define MSR_AMD64_SNP_ALTERNATE_INJ_BIT 6 +#define MSR_AMD64_SNP_ALTERNATE_INJ BIT_ULL(MSR_AMD64_SNP_ALTERNATE_INJ_BIT)#define MSR_AMD64_SNP_DEBUG_SWAP_BIT 7#define MSR_AMD64_SNP_DEBUG_SWAP BIT_ULL(MSR_AMD64_SNP_DEBUG_SWAP_BIT)#define MSR_AMD64_SNP_PREVENT_HOST_IBS_BIT 8
Signature · 1 line
2.43.0
PATCH v2 3/8 x86/apic: Add an SVSM APIC driver
In reply to Melody WangAlternate Injection replaces hypervisor-based interrupt queuing and event injection, requiring guest-controlled queuing and injection. In order to perform this guest-controlled queuing and injection, an SVSM is used to update the guest VMSA to perform the required actions.
The guest uses the SVSM APIC protocol to communicate with the SVSM to perform selected APIC related operations instead of using standard APIC MSR access.
Add such a SVSM APIC driver (which implements a subset of an X2APIC), for the APIC emulation supported by the SVSM.
--- arch/x86/include/asm/sev-common.h | 1 + arch/x86/include/asm/sev.h | 9 ++ arch/x86/kernel/apic/Makefile | 1 + arch/x86/kernel/apic/x2apic_svsm.c | 236 +++++++++++++++++++++++++++++ 4 files changed, 247 insertions(+) create mode 100644 arch/x86/kernel/apic/x2apic_svsm.c
arch/x86/include/asm/sev-common.h +1 -0
@@ -209,6 +209,7 @@ struct snp_psc_desc {#define GHCB_TERM_SECURE_TSC 10/* Secure TSC initialization failed */ #define GHCB_TERM_SVSM_CA_REMAP_FAIL 11/* SVSM is present but CA could not be remapped */ #define GHCB_TERM_SAVIC_FAIL 12/* Secure AVIC-specific failure */ +#define GHCB_TERM_ALT_INJ_FAIL 13/* Alternate Injection-specific failure */ #define GHCB_RESP_CODE (v) ((v) & GHCB_MSR_INFO_MASK)
arch/x86/include/asm/sev.h +9 -0
@@ -435,6 +435,13 @@ struct svsm_call {#define SVSM_VTPM_QUERY 0#define SVSM_VTPM_CMD 1 +#define SVSM_APIC_CALL (x) ((3ULL << 32) | (x)) +#define SVSM_APIC_QUERY_FEATURES 0 +#define SVSM_APIC_CONFIG_EMULATION 1 +#define SVSM_APIC_READ_REGISTER 2 +#define SVSM_APIC_WRITE_REGISTER 3 +#define SVSM_APIC_CONFIG_VECTOR 4 +#ifdef CONFIG_AMD_MEM_ENCRYPT extern u8 snp_vmpl;
@@ -528,6 +535,7 @@ void snp_msg_free(struct snp_msg_desc *mdesc);int snp_send_guest_request (struct snp_msg_desc *mdesc,struct snp_guest_req *req);int snp_svsm_vtpm_send_command (u8 *buffer); +int svsm_perform_call_protocol (struct svsm_call *call);void __init snp_secure_tsc_prepare (void );void __init snp_secure_tsc_init (void );
@@ -636,6 +644,7 @@ static inline void snp_msg_free(struct snp_msg_desc *mdesc) { }static inline int snp_send_guest_request (struct snp_msg_desc *mdesc,struct snp_guest_req *req) {return -ENODEV ; }static inline int snp_svsm_vtpm_send_command (u8 *buffer) {return -ENODEV ; } +static inline int svsm_perform_call_protocol (struct svsm_call *call) {return -ENODEV ; }static inline void __init snp_secure_tsc_prepare (void ) { }static inline void __init snp_secure_tsc_init (void ) { }static inline void sev_evict_cache (void *va,int npages) {}
arch/x86/kernel/apic/Makefile +1 -0
@@ -19,6 +19,7 @@ ifeq ($(CONFIG_X86_64),y) obj-$(CONFIG_X86_NUMACHIP) += apic_numachip.o obj-$(CONFIG_X86_UV) += x2apic_uv_x.o obj-$(CONFIG_AMD_SECURE_AVIC) += x2apic_savic.o +obj-$(CONFIG_AMD_ALTERNATE_INJ) += x2apic_svsm.o obj-$(CONFIG_X86_X2APIC) += x2apic_phys.o obj-$(CONFIG_X86_X2APIC) += x2apic_cluster.o obj-y += apic_flat_64.o
arch/x86/kernel/apic/x2apic_svsm.c new file +236 -0
236 lines not on this page · raw message
Signature · 1 line
2.43.0
PATCH v2 4/8 x86/sev: Route unsupported APIC register accesses to the hypervisor APIC emulation
In reply to Melody WangThe SVSM APIC emulation supports only a subset of the X2APIC MSRs. Right now only basic APIC functionality related to interrupt delivery is supported. Therefore, route the unsupported ones to the hypervisor's X2APIC emulation.
--- arch/x86/coco/sev/core.c | 46 +++++++++++------------------ arch/x86/include/asm/sev-common.h | 1 + arch/x86/include/asm/sev.h | 8 ++--- arch/x86/kernel/apic/x2apic_savic.c | 8 ++--- arch/x86/kernel/apic/x2apic_svsm.c | 11 +++++-- 5 files changed, 35 insertions(+), 39 deletions(-)
arch/x86/coco/sev/core.c +17 -29
@@ -972,7 +972,7 @@ int __init sev_es_efi_map_ghcbs_cas(pgd_t *pgd)return 0 ; } -u64 savic_ghcb_msr_read (u32 reg) +static u64 __sev_apic_ghcb_msr_rw (u32 reg,u64 value,bool write) {u64 msr =APIC_BASE_MSR + (reg >>4 );struct pt_regs regs = { .cx = msr };
@@ -981,49 +981,37 @@ u64 savic_ghcb_msr_read(u32 reg)enum es_result res;struct ghcb *ghcb; +if (write) { + regs.ax =lower_32_bits (value); + regs.dx =upper_32_bits (value); + } +guard (irqsave)(); ghcb =__sev_get_ghcb (&state);vc_ghcb_invalidate (ghcb); - res =__vc_handle_msr (ghcb, &ctxt, false); + res =__vc_handle_msr (ghcb, &ctxt, write);if (res !=ES_OK ) { -pr_err ("Secure AVIC MSR (0x%llx) read returned error (%d)\n" , msr, res); -/* MSR read failures are treated as fatal errors */ -sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_SAVIC_FAIL ); +pr_err ("APIC MSR via GHCB (0x%llx) %s returned error (%d)\n" , msr, write ?"write" :"read" , res); +/* MSR read/write failures are treated as fatal errors */ +sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_APIC_MSR_FAIL ); }__sev_put_ghcb (&state); +/* The return value will be ignored by the caller for a write */ return regs.ax | regs.dx <<32 ; } -void savic_ghcb_msr_write (u32 reg,u64 value) +u64 sev_apic_ghcb_msr_read (u32 reg) { -u64 msr =APIC_BASE_MSR + (reg >>4 ); -struct pt_regs regs = { - .cx = msr, - .ax =lower_32_bits (value), - .dx =upper_32_bits (value) - }; -struct es_em_ctxt ctxt = { .regs = ®s }; -struct ghcb_state state; -enum es_result res; -struct ghcb *ghcb; - -guard (irqsave)(); - - ghcb =__sev_get_ghcb (&state); -vc_ghcb_invalidate (ghcb); - - res =__vc_handle_msr (ghcb, &ctxt, true); -if (res !=ES_OK ) { -pr_err ("Secure AVIC MSR (0x%llx) write returned error (%d)\n" , msr, res); -/* MSR writes should never fail. Any failure is fatal error for SNP guest */ -sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_SAVIC_FAIL ); - } +return __sev_apic_ghcb_msr_rw (reg,0 , false); +} -__sev_put_ghcb (&state); +void sev_apic_ghcb_msr_write (u32 reg,u64 value) +{ +__sev_apic_ghcb_msr_rw (reg, value, true); }enum es_result savic_register_gpa (u64 gpa)
arch/x86/include/asm/sev-common.h +1 -0
@@ -210,6 +210,7 @@ struct snp_psc_desc {#define GHCB_TERM_SVSM_CA_REMAP_FAIL 11/* SVSM is present but CA could not be remapped */ #define GHCB_TERM_SAVIC_FAIL 12/* Secure AVIC-specific failure */ #define GHCB_TERM_ALT_INJ_FAIL 13/* Alternate Injection-specific failure */ +#define GHCB_TERM_APIC_MSR_FAIL 14/* APIC MSR failure */ #define GHCB_RESP_CODE (v) ((v) & GHCB_MSR_INFO_MASK)
arch/x86/include/asm/sev.h +4 -4
@@ -541,8 +541,8 @@ void __init snp_secure_tsc_prepare(void);void __init snp_secure_tsc_init (void );enum es_result savic_register_gpa (u64 gpa);enum es_result savic_unregister_gpa (u64 *gpa); -u64 savic_ghcb_msr_read (u32 reg); -void savic_ghcb_msr_write (u32 reg,u64 value); +u64 sev_apic_ghcb_msr_read (u32 reg); +void sev_apic_ghcb_msr_write (u32 reg,u64 value); static __always_inline void vc_ghcb_invalidate(struct ghcb *ghcb) {
@@ -650,8 +650,8 @@ static inline void __init snp_secure_tsc_init(void) { }static inline void sev_evict_cache (void *va,int npages) {}static inline enum es_result savic_register_gpa (u64 gpa) {return ES_UNSUPPORTED ; }static inline enum es_result savic_unregister_gpa (u64 *gpa) {return ES_UNSUPPORTED ; } -static inline void savic_ghcb_msr_write (u32 reg,u64 value) { } -static inline u64 savic_ghcb_msr_read (u32 reg) {return 0 ; } +static inline void sev_apic_ghcb_msr_write (u32 reg,u64 value) { } +static inline u64 sev_apic_ghcb_msr_read (u32 reg) {return 0 ; }#endif /* CONFIG_AMD_MEM_ENCRYPT */
arch/x86/kernel/apic/x2apic_savic.c +4 -4
@@ -72,7 +72,7 @@ static u32 savic_read(u32 reg)case APIC_LVT0 :case APIC_LVT1 :case APIC_LVTERR : -return savic_ghcb_msr_read (reg); +return sev_apic_ghcb_msr_read (reg);case APIC_ID :case APIC_LVR :case APIC_TASKPRI :
@@ -193,7 +193,7 @@ static void savic_icr_write(u32 icr_low, u32 icr_high) icr_data = ((u64 )icr_high) <<32 | icr_low;if (dsh !=APIC_DEST_SELF ) -savic_ghcb_msr_write (APIC_ICR , icr_data); +sev_apic_ghcb_msr_write (APIC_ICR , icr_data);apic_set_reg64 (this_cpu_ptr (savic_page),APIC_ICR , icr_data); }
@@ -210,7 +210,7 @@ static void savic_write(u32 reg, u32 data)case APIC_LVTTHMR :case APIC_LVTPC :case APIC_LVTERR : -savic_ghcb_msr_write (reg, data); +sev_apic_ghcb_msr_write (reg, data);break ;case APIC_TASKPRI :case APIC_EOI :
@@ -316,7 +316,7 @@ static void savic_eoi(void)* interrupts. Return to the guest from GHCB protocol event takes * care of re-evaluating interrupt state. */ -savic_ghcb_msr_write (APIC_EOI ,0 ); +sev_apic_ghcb_msr_write (APIC_EOI ,0 ); }else {/* * Hardware clears APIC_ISR and re-evaluates the interrupt state
arch/x86/kernel/apic/x2apic_svsm.c +9 -2
@@ -81,8 +81,15 @@ static u32 __svsm_apic_msr_rw(u32 reg, u32 v, bool write) }break ;default : -pr_err ("%s 0x%x not supported\n" , call_reg_str, reg); -return 0 ; +if (write) { +/* +* Even if this will end up returning call.rdx_out, +* that is being ignored by the caller for a write. +*/ +sev_apic_ghcb_msr_write (reg, v); + }else { +return sev_apic_ghcb_msr_read (reg); + } }return call.rdx_out;
Signature · 1 line
2.43.0
PATCH v2 5/8 x86/sev: Add a function to contain all SEV-specific setup operations
In reply to Melody WangTo make the code clean in the boot phase, add a sev_prepare() wrapper which contains early SEV-specific checks in order to have all that code in a single place.
No functional changes.
--- arch/x86/boot/compressed/sev.c | 11 +++++++++++ arch/x86/include/asm/sev.h | 3 +++ drivers/firmware/efi/libstub/x86-stub.c | 17 +++-------------- 3 files changed, 17 insertions(+), 14 deletions(-)
arch/x86/boot/compressed/sev.c +11 -0
@@ -511,3 +511,14 @@ bool early_is_sevsnp_guest(void) }return true; } + +bool sev_prepare (void ) +{ +u64 unsupported =snp_get_unsupported_features (sev_get_status ()); +if (unsupported) { +error ("Unsupported SEV-SNP features detected\n" ); +return true; + } + +return false; +}
arch/x86/include/asm/sev.h +3 -0
@@ -605,6 +605,8 @@ static inline void sev_evict_cache(void *va, int npages) } } +bool sev_prepare (void ); +#else /* !CONFIG_AMD_MEM_ENCRYPT */ #define snp_vmpl 0
@@ -652,6 +654,7 @@ static inline enum es_result savic_register_gpa(u64 gpa) { return ES_UNSUPPORTEDstatic inline enum es_result savic_unregister_gpa (u64 *gpa) {return ES_UNSUPPORTED ; }static inline void sev_apic_ghcb_msr_write (u32 reg,u64 value) { }static inline u64 sev_apic_ghcb_msr_read (u32 reg) {return 0 ; } +static inline bool sev_prepare (void ) {return false; }#endif /* CONFIG_AMD_MEM_ENCRYPT */
drivers/firmware/efi/libstub/x86-stub.c +3 -14
@@ -783,19 +783,6 @@ static efi_status_t exit_boot(struct boot_params *boot_params, void *handle)return EFI_SUCCESS ; } -static bool have_unsupported_snp_features (void ) -{ -u64 unsupported; - - unsupported =snp_get_unsupported_features (sev_get_status ()); -if (unsupported) { -efi_err ("Unsupported SEV-SNP features detected: 0x%llx\n" , - unsupported); -return true; - } -return false; -} -static void efi_get_seed (void *seed,int size) {efi_get_random_bytes (size, seed);
@@ -919,6 +906,7 @@ void __noreturn efi_stub_entry(efi_handle_t handle,unsigned long kernel_entry;struct setup_header *hdr;efi_status_t status; +bool err; efi_system_table = sys_table_arg;/* Check if we were booted by the EFI firmware */
@@ -933,7 +921,8 @@ void __noreturn efi_stub_entry(efi_handle_t handle, hdr = &boot_params->hdr; -if (have_unsupported_snp_features ()) + err =sev_prepare (); +if (err)efi_exit (handle,EFI_UNSUPPORTED );if (IS_ENABLED (CONFIG_EFI_DXE_MEM_ATTRIBUTES )) {
Signature · 1 line
2.43.0
Ard Biesheuvel
maintainerRe: [PATCH v2 5/8] x86/sev: Add a function to contain all SEV-specific setup operations
Quoted 18 lines · Melody Wang
To make the code clean in the boot phase, add a
sev_prepare()wrapper which contains early SEV-specific checks in order to have all that code in a single place.No functional changes.
Signed-off-by Melody Wang <[email protected]>--- arch/x86/boot/compressed/sev.c | 11 +++++++++++ arch/x86/include/asm/sev.h | 3 +++ drivers/firmware/efi/libstub/x86-stub.c | 17 +++-------------- 3 files changed, 17 insertions(+), 14 deletions(-)arch/x86/boot/compressed/sev.c +0
-0
arch/x86/boot/compressed/sev.c bool early_is_sevsnp_guest(void) · line 519
Quoted 9 lines
arch/x86/boot/compressed/sev.c +6
-0@@ -511,3 +511,14 @@ bool early_is_sevsnp_guest(void) }return true; } + +bool sev_prepare (void ) +{ +u64 unsupported =snp_get_unsupported_features (sev_get_status ()); +if (unsupported) { +error ("Unsupported SEV-SNP features detected\n" );
The EFI stub will call this while running under the boot services, so error() should not be used here.
Also, error() never returns - it is the decompressor's pseudo-panic() so whatever you return to will never execute.
Quoted 74 lines
arch/x86/boot/compressed/sev.c +5
-0+return true; + } + +return false; +}arch/x86/include/asm/sev.h +2
-0@@ -605,6 +605,8 @@ static inline void sev_evict_cache(void *va, int npages) } } +bool sev_prepare (void ); +#else /* !CONFIG_AMD_MEM_ENCRYPT */ #define snp_vmpl 0@@ -652,6 +654,7 @@ static inline enum es_result savic_register_gpa(u64gpa) { return
ES_UNSUPPORTED
static inline enumes_resultsavic_unregister_gpa(u64 *gpa){ returnES_UNSUPPORTED; }
static inline voidsev_apic_ghcb_msr_write(u32 reg, u64 value){ } static inline u64sev_apic_ghcb_msr_read(u32 reg){ return 0; }arch/x86/include/asm/sev.h +1
-0+static inline bool sev_prepare (void ) {return false; }#endif /* CONFIG_AMD_MEM_ENCRYPT */ drivers/firmware/efi/libstub/x86-stub.c +0
-13@@ -783,19 +783,6 @@ static efi_status_t exit_boot(struct boot_params *boot_params, void *handle)return EFI_SUCCESS ; } -static bool have_unsupported_snp_features (void ) -{ -u64 unsupported; - - unsupported =snp_get_unsupported_features (sev_get_status ()); -if (unsupported) { -efi_err ("Unsupported SEV-SNP features detected: 0x%llx\n" , - unsupported); -return true; - } -return false; -} -static void efi_get_seed (void *seed,int size) {drivers/firmware/efi/libstub/x86-stub.c +3
-1efi_get_random_bytes (size, seed);@@ -919,6 +906,7 @@ void __noreturn efi_stub_entry(efi_handle_t handle,unsigned long kernel_entry;struct setup_header *hdr;efi_status_t status; +bool err; efi_system_table = sys_table_arg;/* Check if we were booted by the EFI firmware */ @@ -933,7 +921,8 @@ void __noreturn efi_stub_entry(efi_handle_t handle, hdr = &boot_params->hdr; -if (have_unsupported_snp_features ()) + err =sev_prepare (); +if (err)efi_exit (handle,EFI_UNSUPPORTED );if (IS_ENABLED (CONFIG_EFI_DXE_MEM_ATTRIBUTES )) {Signature · 1 line
2.43.0
PATCH v2 6/8 x86/sev: Register the guest with the SVSM APIC protocol
In reply to Melody WangThe SVSM APIC protocol supports 5 calls. SVSM_APIC_CONFIGURE_EMULATION (shortened to SVSM_APIC_CONFIG_EMULATION for brevity), call 1, provides the controls whether the guest can make use of the SVSM APIC protocol.
Implement this call, and register Alternate Injection for the guest by default.
--- arch/x86/boot/compressed/sev.c | 17 +++++++++++++++++ arch/x86/boot/compressed/sev.h | 6 ++++++ 2 files changed, 23 insertions(+)
arch/x86/boot/compressed/sev.c +17 -0
@@ -520,5 +520,22 @@ bool sev_prepare(void)return true; } +/* Register Alternate Injection */ +if (early_is_sevsnp_guest () && snp_vmpl) { +struct svsm_call call = {}; +int ret; + +if (!(sev_get_status () &MSR_AMD64_SNP_ALTERNATE_INJ )) +return false; + + call.caa = (struct svsm_ca *)boot_svsm_caa_pa; + call.rax =SVSM_APIC_CALL (SVSM_APIC_CONFIG_EMULATION ); + call.rcx =SVSM_AI_REGISTER ; + + ret =svsm_call_msr_protocol (&call); +if (ret) +sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_ALT_INJ_FAIL ); + } +return false; }
arch/x86/boot/compressed/sev.h +6 -0
@@ -12,6 +12,12 @@#include <asm/shared/msr.h> +enum svsm_ai_ctrl { +SVSM_AI_DISABLE , +SVSM_AI_DEREGISTER , +SVSM_AI_REGISTER , +}; +void snp_accept_memory (phys_addr_t start,phys_addr_t end);u64 sev_get_status (void );bool early_is_sevsnp_guest (void );
Signature · 1 line
2.43.0
Ard Biesheuvel
maintainerRe: [PATCH v2 6/8] x86/sev: Register the guest with the SVSM APIC protocol
Quoted 4 lines · Melody Wang
The SVSM APIC protocol supports 5 calls.
SVSM_APIC_CONFIGURE_EMULATION(shortened toSVSM_APIC_CONFIG_EMULATIONfor brevity), call 1, provides the controls whether the guest can make use of the SVSM APIC protocol.
Quoted 9 lines
Implement this call, and register Alternate Injection for the guest by default.
Signed-off-by Melody Wang <[email protected]>--- arch/x86/boot/compressed/sev.c | 17 +++++++++++++++++ arch/x86/boot/compressed/sev.h | 6 ++++++ 2 files changed, 23 insertions(+)
Does this need to happen in the EFI stub and/or decompressor? We have swathes of early SEV-SNP boot code in the kernel proper; could it be done there?
Re: [PATCH v2 6/8] x86/sev: Register the guest with the SVSM APIC protocol
Hi Ard,
Quoted 15 lines · Ard Biesheuvel
Quoted 4 lines · Melody Wang
The SVSM APIC protocol supports 5 calls.
SVSM_APIC_CONFIGURE_EMULATION(shortened toSVSM_APIC_CONFIG_EMULATIONfor brevity), call 1, provides the controls whether the guest can make use of the SVSM APIC protocol.Quoted 9 lines
Implement this call, and register Alternate Injection for the guest by default.
Signed-off-by Melody Wang <[email protected]>--- arch/x86/boot/compressed/sev.c | 17 +++++++++++++++++ arch/x86/boot/compressed/sev.h | 6 ++++++ 2 files changed, 23 insertions(+)
Quoted 2 lines
Does this need to happen in the EFI stub and/or decompressor? We have swathes of early SEV-SNP boot code in the kernel proper; could it be done there?
Let me answer the question directly first:
Alternate Injection is used by both the guest firmware and the guest kernel. Before we run the guest kernel, guest firmware - OVMF - is using Alternate Injection for interrupts, etc.
So ExitBootServices() is a handoff boundary. When it is called, the firmware's use of Alternate Injection ends. It must deregister its use of Alternate Injection at this point since it can not assume anything about the guest kernel that follows.
At this moment, if the guest kernel has not registered the use of Alternate Injection, latter is disabled and can not be re-enabled.
So if the guest kernel wants Alternate Injection, it has to happen before ExitBootServices().
I hope this answers the question, the rest below is a longer, more detailed explanation which you don't necessarily need to read - only if you're interested.
:)
Now here's the long explanation along with the spec on the matter:
There is an Alternate Injection spec (I'm attaching it because the mailing list archives which hosted it, are not up currently) and it says that Alternate Injection supports multiple guest runtimes, see the "Negotiating Functionality" section.
When there is a handoff from a UEFI virtual firmware to a guest operating system, the firmware, before terminating its execution must be prepared to disable the use of Alternate Injection unless it knows the guest kernel is prepared to continue use of Alternate Injection.
However, there is no mechanism for them to negotiate this directly, so the SVSM APIC protocol supports a registration mechanism to determine the behavior across handoff by using a registration counter.
The spec has an example how this mechanism might be used in the case of transition from UEFI-based firmware to a guest OS:
"Prior to executing ExitBootServices, a guest OS that understands the SVSM APIC Protocol should detect the availability of that protocol and determine whether it is usable. If so, it should register its use of the SVSM APIC Protocol.
During the execution of ExitBootServices, the firmware (which does not know the intention of the guest OS) should deregister its use of the SVSM APIC protocol. If the guest OS registered its intention to use Alternate Injection, this call will not affect the current state of Alternate Injection. If the guest OS did not declare its intention to use Alternate Injection, then this call will disable Alternate Injection."
During the handoff, the firmware needs to deresgister its use of Alternate Injection, so the registration counter can reflect the right status of using Alternate Injection for runtimes. Once the registration count reaches zero, Alternate Injection is disabled and cannot be re-enabled, so if the guest OS wants Alternate Injection, it has to register before ExitBootServices() to keep the count > 0.
I hope that makes sense.
Signature · 2 lines
Thanks, Melody
Ard Biesheuvel
maintainerRe: [PATCH v2 6/8] x86/sev: Register the guest with the SVSM APIC protocol
Quoted 32 lines · Melody Wang
Hi Ard,
Quoted 15 lines · Ard Biesheuvel
Quoted 4 lines · Melody Wang
The SVSM APIC protocol supports 5 calls.
SVSM_APIC_CONFIGURE_EMULATION(shortened toSVSM_APIC_CONFIG_EMULATIONfor brevity), call 1, provides the controls whether the guest can make use of the SVSM APIC protocol.Quoted 9 lines
Implement this call, and register Alternate Injection for the guest by default.
Signed-off-by Melody Wang <[email protected]>--- arch/x86/boot/compressed/sev.c | 17 +++++++++++++++++ arch/x86/boot/compressed/sev.h | 6 ++++++ 2 files changed, 23 insertions(+)Quoted 2 lines
Does this need to happen in the EFI stub and/or decompressor? We have swathes of early SEV-SNP boot code in the kernel proper; could it be done there?
Let me answer the question directly first:
Alternate Injection is used by both the guest firmware and the guest kernel. Before we run the guest kernel, guest firmware - OVMF - is using Alternate Injection for interrupts, etc.
So
ExitBootServices()is a handoff boundary. When it is called, the firmware's use of Alternate Injection ends. It must deregister its use of Alternate Injection at this point since it can not assume anything about the guest kernel that follows.
Quoted 6 lines
At this moment, if the guest kernel has not registered the use of Alternate Injection, latter is disabled and can not be re-enabled.
So if the guest kernel wants Alternate Injection, it has to happen before
ExitBootServices().
OK, so this means that this code will only be called from the EFI stub running under EFI boot services, and never from the decompressor when doing traditional boot.
So please add it to the EFI stub, and code it against the boot services (efi_err() for error messages, efi_exit() when aborting and returning to the firmware, etc). Implementing this in a hybrid manner seems entirely unnecessary.
Re: [PATCH v2 6/8] x86/sev: Register the guest with the SVSM APIC protocol
Hi Ard,
Quoted 4 lines · Ard Biesheuvel
So please add it to the EFI stub, and code it against the boot services (
efi_err()for error messages,efi_exit()when aborting and returning to the firmware, etc). Implementing this in a hybrid manner seems entirely unnecessary.
I moved sev_prepare() into the EFI stub, and I wrote a wrapper for registering Alternate Injection in the EFI stub but kept the code in compressed, otherwise I have to export early_is_sevsnp_guest(), boot_svsm_caa_pa, and svsm_call_msr_protocol() so that it builds.
How about this below:
This is in the stub:
static bool sev_prepare(void)
{
u64 unsupported;
unsupported = snp_get_unsupported_features(sev_get_status());
if (unsupported) {
efi_err("Unsupported SEV-SNP features detected: 0x%llx\n",
unsupported);
return true;
}
register_alternate_injection();
return false;
}and the stub calls this function:
+void register_alternate_injection(void)
+{
+ if (early_is_sevsnp_guest() && snp_vmpl) {
+ struct svsm_call call = {};
+ int ret;
+
+ if (!(sev_get_status() & MSR_AMD64_SNP_ALTERNATE_INJ))
+ return;
+
+ call.caa = (struct svsm_ca *)boot_svsm_caa_pa; + call.rax = SVSM_APIC_CALL(SVSM_APIC_CONFIG_EMULATION); + call.rcx = SVSM_AI_REGISTER;
+
+ ret = svsm_call_msr_protocol(&call);
+ if (ret)
+ sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_ALT_INJ_FAIL);
+ }
+}
which is kept in sev.c to avoid cross-dependencies.
I can send it as patches too if it is easier to review this way.
Signature · 2 lines
Thanks, Melody
Ard Biesheuvel
maintainerRe: [PATCH v2 6/8] x86/sev: Register the guest with the SVSM APIC protocol
Quoted 8 lines · Melody Wang
Hi Ard,
Quoted 4 lines · Ard Biesheuvel
So please add it to the EFI stub, and code it against the boot services (
efi_err()for error messages,efi_exit()when aborting and returning to the firmware, etc). Implementing this in a hybrid manner seems entirely unnecessary.
Quoted 5 lines
I moved
sev_prepare()into the EFI stub, and I wrote a wrapper for registering Alternate Injection in the EFI stub but kept the code in compressed, otherwise I have to exportearly_is_sevsnp_guest(),boot_svsm_caa_pa, andsvsm_call_msr_protocol()so that it builds.
early_is_sevsnp_guest() needs to be exported anyway, as I am doing in [0]
Quoted 42 lines
How about this below:
This is in the stub:
static bool
sev_prepare(void){ u64 unsupported; unsupported = snp_get_unsupported_features(sev_get_status()); if (unsupported) { efi_err("Unsupported SEV-SNP features detected: 0x%llx\n", unsupported); return true; } register_alternate_injection(); return false; }and the stub calls this function:
arch/x86/boot/compressed/sev.c +16
-0+void register_alternate_injection (void ) +{ +if (early_is_sevsnp_guest () && snp_vmpl) { +struct svsm_call call = {}; +int ret; + +if (!(sev_get_status () &MSR_AMD64_SNP_ALTERNATE_INJ )) +return ; + + call.caa = (struct svsm_ca *)boot_svsm_caa_pa; + call.rax =SVSM_APIC_CALL (SVSM_APIC_CONFIG_EMULATION ); + call.rcx =SVSM_AI_REGISTER ; + + ret =svsm_call_msr_protocol (&call); +if (ret) + sev_es_terminate(SEV_TERM_SET_LINUX,
GHCB_TERM_ALT_INJ_FAIL);(quoted diff) +2
-0+ } +}
Quoted 2 lines
which is kept in
sev.cto avoid cross-dependencies.
Yes, that seems fine. The important thing is that the SEV support code that is shared between the EFI stub, the legacy decompressor and the kernel proper has no dependencies on the underlying execution context, e.g., EFI boot services or decompressor APIs.
Quoted 2 lines
I can send it as patches too if it is easier to review this way.
Naturally.
Re: [PATCH v2 6/8] x86/sev: Register the guest with the SVSM APIC protocol
Hi Ard,
Quoted 1 line · Ard Biesheuvel
early_is_sevsnp_guest()needs to be exported anyway, as I am doing in [0]
I see, I can export it when it is needed.
Right now, I think I can put the code in compressed/sev.c since those functions are self-contained as you noted.
If it is really necessary and we want to be pedantic, we can carve them out into a separate compilation unit but that's for later.
I will send v3 and cc you.
Thanks,
Melody
PATCH v2 7/8 x86/sev: Allow the guest to configure interrupt vectors for the hypervisor
In reply to Melody WangThe SVSM APIC protocol supports 5 API calls. SVSM_APIC_CONFIGURE_VECTOR (shortened to SVSM_APIC_CONFIG_VECTOR for brevity), call 4, provides for the guest to configure an interrupt vector which the guest allows and the hypervisor can use to signal interrupts for it.
Implement this call, and make the default interrupt setting permissive to allow all interrupts when detecting an SVSM and Alternate Injection is enabled.
--- arch/x86/boot/compressed/sev.c | 13 ++++++++++++- arch/x86/boot/compressed/sev.h | 7 +++++++ 2 files changed, 19 insertions(+), 1 deletion(-)
arch/x86/boot/compressed/sev.c +12 -1
@@ -520,7 +520,11 @@ bool sev_prepare(void)return true; } -/* Register Alternate Injection */ +/* +* When the guest is running at VMPL2 with Alternate Injection enabled, +* register Alternate Injection, and configure all of interrupts as +* permissive by default. +*/ if (early_is_sevsnp_guest () && snp_vmpl) {struct svsm_call call = {};int ret;
@@ -532,6 +536,13 @@ bool sev_prepare(void) call.rax =SVSM_APIC_CALL (SVSM_APIC_CONFIG_EMULATION ); call.rcx =SVSM_AI_REGISTER ; + ret =svsm_call_msr_protocol (&call); +if (ret) +sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_ALT_INJ_FAIL ); + + call.rax =SVSM_APIC_CALL (SVSM_APIC_CONFIG_VECTOR ); + call.rcx =SVSM_IRQ_ENABLE_ALL ; + ret =svsm_call_msr_protocol (&call);if (ret)sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_ALT_INJ_FAIL );
arch/x86/boot/compressed/sev.h +7 -0
@@ -18,6 +18,13 @@ enum svsm_ai_ctrl { SVSM_AI_REGISTER, }; +enum svsm_vec_enable { +SVSM_IRQ_DISABLE_SINGLE = (0u <<8 ), +SVSM_IRQ_ENABLE_SINGLE = (1u <<8 ), +SVSM_IRQ_DISABLE_ALL = (2u <<8 ), +SVSM_IRQ_ENABLE_ALL = (3u <<8 ), +}; +void snp_accept_memory (phys_addr_t start,phys_addr_t end);u64 sev_get_status (void );bool early_is_sevsnp_guest (void );
Signature · 1 line
2.43.0
PATCH v2 8/8 x86/sev: Indicate that Alternate Injection is supported in the guest
In reply to Melody WangNow the Alternate Injection support is complete, add it to the present SNP features.
--- arch/x86/boot/compressed/sev.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
arch/x86/boot/compressed/sev.c +8 -1
@@ -197,6 +197,12 @@ bool sev_es_check_ghcb_fault(unsigned long address)#define SNP_FEATURE_SECURE_AVIC 0#endif +#ifdef CONFIG_AMD_ALTERNATE_INJ +#define SNP_FEATURE_ALTERNATE_INJ MSR_AMD64_SNP_ALTERNATE_INJ +#else +#define SNP_FEATURE_ALTERNATE_INJ 0 +#endif +/* * SNP_FEATURES_IMPL is the mask of SNP features that are implemented * by the guest kernel. As and when a new feature is implemented in the
@@ -204,7 +210,8 @@ bool sev_es_check_ghcb_fault(unsigned long address)*/ #define SNP_FEATURES_IMPL (MSR_AMD64_SNP_DEBUG_SWAP | \ MSR_AMD64_SNP_SECURE_TSC | \ - SNP_FEATURE_SECURE_AVIC) + SNP_FEATURE_SECURE_AVIC | \ + SNP_FEATURE_ALTERNATE_INJ)u64 snp_get_unsupported_features (u64 status) {
Signature · 1 line
2.43.0