Alternate Injection: Secure Interrupt Delivery for SEV-SNP Guests - Guest Support
v6 cover Alternate Injection: Secure Interrupt Delivery for SEV-SNP Guests - Guest Support
Hi all,
This revision addresses all version 5 review comments from Sashiko.
Key Changes
1. svsm_apic driver cleanups: Removed the read-only MSR from the SVSM APIC filter in svsm_apic_msr_write(), and the write-only MSR from svsm_apic_msr_read().
2. Clarified and updated the commit message for patch 5 to improve readability and context.
Thanks,
Melody
Changelog:
v5
--
This revision addresses all review comments from version 4.
1. As Ard suggested, used a bool as return value for svsm_register_alt_inj() instead of int. Adjusted code with it.
2. Added more comments here for better understanding.
Changelog:
v4
--
This revision addresses all review comments from version 3.
1. As Ard suggested, handed over the registeration of kernel guest for Alternate Injection with the SVSM to the OVMF insteading of calling the SVSM for registration from kernel guest before ExitBootsService().
2. Added a common function for SVSM APIC ICR read and write.
3. Added a common function for sev_apic_ghcb_msr_read/write.
4. Changed some comments for better understanding.
5. Patch "Make-SVSM-calls-preemption-safe.patch" was merged to the tip tree.
v3
--
This revision addresses all review comments from version 2.
The changes include:
1. Moved sev_prepare() from decompressor to EFI stub.
2. Changed "Register Alternate Injection" and "configure all interrupt vectors" as two APIs located in compressed/sev.c since they are self-contained, avoiding exporting functions.
3. Added more comments for better understanding.
v2
--
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.
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 (7):
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 Alternate Injection protocol during OVMF boot 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 | 11 +- arch/x86/boot/startup/sev-startup.c | 20 ++ arch/x86/boot/startup/sme.c | 3 + arch/x86/coco/core.c | 3 + arch/x86/coco/sev/core.c | 48 ++--- arch/x86/include/asm/msr-index.h | 4 +- arch/x86/include/asm/sev-common.h | 2 + arch/x86/include/asm/sev.h | 26 ++- arch/x86/kernel/apic/Makefile | 1 + arch/x86/kernel/apic/x2apic_savic.c | 8 +- arch/x86/kernel/apic/x2apic_svsm.c | 253 ++++++++++++++++++++++++ drivers/firmware/efi/libstub/efistub.h | 11 ++ drivers/firmware/efi/libstub/x86-stub.c | 42 +++- include/linux/cc_platform.h | 8 + include/linux/efi.h | 2 + tools/arch/x86/include/asm/msr-index.h | 4 +- 17 files changed, 412 insertions(+), 48 deletions(-) create mode 100644 arch/x86/kernel/apic/x2apic_svsm.c
Signature · 1 line
2.43.0
PATCH v6 1/7 x86/sev: Add support for Alternate Injection
The 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
@@ -494,6 +494,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
@@ -730,8 +730,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
@@ -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
Signature · 1 line
2.43.0
Borislav Petkov
maintainerRe: [PATCH v6 1/7] x86/sev: Add support for Alternate Injection
Quoted 10 lines · Melody Wang
The 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.
Just commit message touch ups:
Alternate Injection is a method to protect a SNP guest from malicious injection attacks by allowing the guest to control the 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.
Signature · 4 lines
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquettePATCH v6 2/7 x86/apic: Add an SVSM APIC driver
In reply to Melody WangAlternate Injection replaces hypervisor-based interrupt queuing and event injection in favor of guest-controlled queuing and injection. In order to complish that, 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 | 252 +++++++++++++++++++++++++++++ 4 files changed, 263 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;
@@ -529,6 +536,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 );
@@ -638,6 +646,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 +252 -0
252 lines not on this page · raw message
Signature · 1 line
2.43.0
PATCH v6 3/7 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 | 9 +++--- 5 files changed, 31 insertions(+), 41 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
@@ -542,8 +542,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) {
@@ -652,8 +652,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 +5 -4
@@ -68,7 +68,7 @@ static void svsm_apic_msr_write(u32 reg, u32 v) }break ;default : -pr_err ("SVSM_APIC_WRITE_REGISTER 0x%x not supported\n" , reg); +sev_apic_ghcb_msr_write (reg, v);break ; } }
@@ -77,6 +77,7 @@ static u32 svsm_apic_msr_read(u32 reg) {u32 msr =APIC_BASE_MSR + (reg >>4 );struct svsm_call call = {}; +u64 val;int ret;switch (reg) {
@@ -100,17 +101,17 @@ static u32 svsm_apic_msr_read(u32 reg) call.rcx = msr; ret =svsm_perform_call_protocol (&call); + val = call.rdx_out;if (ret) {pr_err ("SVSM_APIC_READ_REGISTER: 0x%x, error: %d\n" , reg, ret);sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_ALT_INJ_FAIL ); }break ;default : -pr_err ("SVSM_APIC_READ_REGISTER: 0x%x not supported\n" , reg); -return 0 ; + val =sev_apic_ghcb_msr_read (reg); } -return call.rdx_out; +return val; }static inline void svsm_apic_msr_eoi (void )
Signature · 1 line
2.43.0
PATCH v6 4/7 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.
--- drivers/firmware/efi/libstub/x86-stub.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/firmware/efi/libstub/x86-stub.c +4 -4
@@ -786,7 +786,7 @@ static efi_status_t exit_boot(struct boot_params *boot_params, void *handle)return EFI_SUCCESS ; } -static bool have_unsupported_snp_features (void ) +static bool sev_prepare (void ) {u64 unsupported;
@@ -794,9 +794,9 @@ static bool have_unsupported_snp_features(void)if (unsupported) {efi_err ("Unsupported SEV-SNP features detected: 0x%llx\n" , unsupported); -return true; +return false; } -return false; +return true; }static void efi_get_seed (void *seed,int size)
@@ -937,7 +937,7 @@ void __noreturn efi_stub_entry(efi_handle_t handle, hdr = &boot_params->hdr; -if (have_unsupported_snp_features ()) +if (!sev_prepare ())efi_exit (handle,EFI_UNSUPPORTED );if (IS_ENABLED (CONFIG_EFI_DXE_MEM_ATTRIBUTES )) {
Signature · 1 line
2.43.0
PATCH v6 5/7 x86/sev: Register Alternate Injection protocol during OVMF boot
In reply to Melody WangThe SVSM provides the SVSM_APIC_CONFIG_EMULATION protocol to register and deregister Alternate Injection. This configuration must be completed before ExitBootServices() is called. Therefore, OVMF needs to invoke this protocol early to set up Alternate Injection for SEV-SNP guests.
Implement this registration by default for guests that have SEV-SNP Alternate Injection enabled.
--- drivers/firmware/efi/libstub/efistub.h | 11 ++++++++ drivers/firmware/efi/libstub/x86-stub.c | 36 ++++++++++++++++++++++++- include/linux/efi.h | 2 ++ 3 files changed, 48 insertions(+), 1 deletion(-)
drivers/firmware/efi/libstub/efistub.h +11 -0
@@ -177,6 +177,17 @@ void efi_set_u64_split(u64 data, u32 *lo, u32 *hi)*/ #define EFI_MMAP_NR_SLACK_SLOTS 32 +typedef union sev_alt_inj_register_protocol sev_alt_inj_register_protocol_t ; +union sev_alt_inj_register_protocol { +struct { + efi_status_t (__efiapi * sev_register_alt_inj) + (sev_alt_inj_register_protocol_t *); + }; +struct { +u32 sev_register_alt_inj; + } mixed_mode; +}; +typedef struct efi_generic_dev_path efi_device_path_protocol_t ;union efi_device_path_to_text_protocol {
drivers/firmware/efi/libstub/x86-stub.c +35 -1
@@ -786,6 +786,39 @@ static efi_status_t exit_boot(struct boot_params *boot_params, void *handle)return EFI_SUCCESS ; } +/* +* When the guest is running at VMPL2 with Alternate Injection enabled, +* register Alternate Injection before ExitBootServices(). +* +* Return true in the first conditional to mean that this is not an Alternate +* Injection guest and boot can continue. If it is an Alternate Injection guest, +* both failure to locate the protocol and to register it, means fail the boot. +*/ +static bool svsm_register_alt_inj (void ) +{ +efi_guid_t alt_inj_proto =OVMF_SEV_ALT_INJ_REGISTER_PROTOCOL_GUID ; +sev_alt_inj_register_protocol_t *proto; +efi_status_t status; + +if (!early_is_sevsnp_guest () || !snp_vmpl || + !(sev_get_status () &MSR_AMD64_SNP_ALTERNATE_INJ )) +return true; + + status =efi_bs_call (locate_protocol, &alt_inj_proto,NULL , (void **)&proto); +if (status !=EFI_SUCCESS ) { +efi_err ("Alternate Injection registration protocol not exist\n" ); +return false; + } + + status =efi_call_proto (proto, sev_register_alt_inj); +if (status !=EFI_SUCCESS ) { +efi_err ("Alternate Injection registration protocol failed\n" ); +return false; + } + +return true; +} +static bool sev_prepare (void ) {u64 unsupported;
@@ -796,7 +829,8 @@ static bool sev_prepare(void) unsupported);return false; } -return true; + +return svsm_register_alt_inj (); }static void efi_get_seed (void *seed,int size)
include/linux/efi.h +2 -0
@@ -444,6 +444,8 @@ void efi_native_runtime_setup(void);#define OVMF_SEV_MEMORY_ACCEPTANCE_PROTOCOL_GUID EFI_GUID(0xc5a010fe, 0x38a7, 0x4531, 0x8a, 0x4a, 0x05, 0x00, 0xd2, 0xfd, 0x16, 0x49)#define OVMF_MEMORY_LOG_TABLE_GUID EFI_GUID(0x95305139, 0xb20f, 0x4723, 0x84, 0x25, 0x62, 0x7c, 0x88, 0x8f, 0xf1, 0x21) +#define OVMF_SEV_ALT_INJ_REGISTER_PROTOCOL_GUID EFI_GUID(0x3cf00587, 0x2329, 0x4c44, 0xb1, 0x84, 0x8f, 0xd9, 0x87, 0x00, 0x42, 0xe0) + typedef struct { efi_guid_t guid; u64 table;
Signature · 1 line
2.43.0
PATCH v6 6/7 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 when detecting an SVSM.
--- arch/x86/boot/startup/sev-startup.c | 20 ++++++++++++++++++++ arch/x86/boot/startup/sme.c | 3 +++ arch/x86/include/asm/sev.h | 9 +++++++++ 3 files changed, 32 insertions(+)
arch/x86/boot/startup/sev-startup.c +20 -0
@@ -191,6 +191,26 @@ static void __init svsm_setup(struct cc_blob_sev_info *cc_info) boot_svsm_caa_pa = pa; } +/* +* Configure all interrupts as permissive by default for Alternate Injection +* enabled SNP guest. +*/ +void __init svsm_config_alt_inj_vectors (void ) +{ +struct svsm_call call = {}; +int ret; + +if (sev_status &MSR_AMD64_SNP_ALTERNATE_INJ ) { + call.caa =rip_rel_ptr (&boot_svsm_ca_page); + call.rax =SVSM_APIC_CALL (SVSM_APIC_CONFIG_VECTOR ); + call.rcx =SVSM_IRQ_ENABLE_ALL <<8 ; + + ret =svsm_call_msr_protocol (&call); +if (ret) +sev_es_terminate (SEV_TERM_SET_LINUX ,GHCB_TERM_ALT_INJ_FAIL ); + } +} +bool __init snp_init (struct boot_params *bp) {struct cc_blob_sev_info *cc_info;
arch/x86/boot/startup/sme.c +3 -0
@@ -566,6 +566,9 @@ void __init sme_enable(struct boot_params *bp) physical_mask &= ~me_mask; cc_vendor =CC_VENDOR_AMD ;cc_set_mask (me_mask); + +if (snp_vmpl) +svsm_config_alt_inj_vectors (); }#ifdef CONFIG_MITIGATION_PAGE_TABLE_ISOLATION
arch/x86/include/asm/sev.h +9 -0
@@ -34,6 +34,13 @@ enum es_result { ES_RETRY, /* Retry instruction emulation */ }; +enum svsm_vec_enable { +SVSM_IRQ_DISABLE_SINGLE , +SVSM_IRQ_ENABLE_SINGLE , +SVSM_IRQ_DISABLE_ALL , +SVSM_IRQ_ENABLE_ALL , +}; +struct es_fault_info {unsigned long vector;unsigned long error_code;
@@ -518,6 +525,7 @@ void snp_set_memory_shared(unsigned long vaddr, unsigned long npages);void snp_set_memory_private (unsigned long vaddr,unsigned long npages);void snp_set_wakeup_secondary_cpu (void );bool snp_init (struct boot_params *bp); +void svsm_config_alt_inj_vectors (void );void snp_dmi_setup (void );int snp_issue_svsm_attest_req (u64 call_id,struct svsm_call *call,struct svsm_attest_call *input);void snp_accept_memory (phys_addr_t start,phys_addr_t end);
@@ -626,6 +634,7 @@ static inline void snp_set_memory_shared(unsigned long vaddr, unsigned long npagstatic inline void snp_set_memory_private (unsigned long vaddr,unsigned long npages) { }static inline void snp_set_wakeup_secondary_cpu (void ) { }static inline bool snp_init (struct boot_params *bp) {return false; } +static inline void svsm_config_alt_inj_vectors (void ) { }static inline void snp_dmi_setup (void ) { }static inline int snp_issue_svsm_attest_req (u64 call_id,struct svsm_call *call,struct svsm_attest_call *input) {
Signature · 1 line
2.43.0
PATCH v6 7/7 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