Commit bc6bc34b authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'x86_urgent_for_v6.2_rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 fixes from Borislav Petkov:

 - Start checking for -mindirect-branch-cs-prefix clang support too now
   that LLVM 16 will support it

 - Fix a NULL ptr deref when suspending with Xen PV

 - Have a SEV-SNP guest check explicitly for features enabled by the
   hypervisor and fail gracefully if some are unsupported by the guest
   instead of failing in a non-obvious and hard-to-debug way

 - Fix a MSI descriptor leakage under Xen

 - Mark Xen's MSI domain as supporting MSI-X

 - Prevent legacy PIC interrupts from being resent in software by
   marking them level triggered, as they should be, which lead to a NULL
   ptr deref

* tag 'x86_urgent_for_v6.2_rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/build: Move '-mindirect-branch-cs-prefix' out of GCC-only block
  acpi: Fix suspend with Xen PV
  x86/sev: Add SEV-SNP guest feature negotiation support
  x86/pci/xen: Fixup fallout from the PCI/MSI overhaul
  x86/pci/xen: Set MSI_FLAG_PCI_MSIX support in Xen MSI domain
  x86/i8259: Mark legacy PIC interrupts with IRQ_LEVEL
parents 80826e90 27b5de62
...@@ -95,3 +95,39 @@ by supplying mem_encrypt=on on the kernel command line. However, if BIOS does ...@@ -95,3 +95,39 @@ by supplying mem_encrypt=on on the kernel command line. However, if BIOS does
not enable SME, then Linux will not be able to activate memory encryption, even not enable SME, then Linux will not be able to activate memory encryption, even
if configured to do so by default or the mem_encrypt=on command line parameter if configured to do so by default or the mem_encrypt=on command line parameter
is specified. is specified.
Secure Nested Paging (SNP)
==========================
SEV-SNP introduces new features (SEV_FEATURES[1:63]) which can be enabled
by the hypervisor for security enhancements. Some of these features need
guest side implementation to function correctly. The below table lists the
expected guest behavior with various possible scenarios of guest/hypervisor
SNP feature support.
+-----------------+---------------+---------------+------------------+
| Feature Enabled | Guest needs | Guest has | Guest boot |
| by the HV | implementation| implementation| behaviour |
+=================+===============+===============+==================+
| No | No | No | Boot |
| | | | |
+-----------------+---------------+---------------+------------------+
| No | Yes | No | Boot |
| | | | |
+-----------------+---------------+---------------+------------------+
| No | Yes | Yes | Boot |
| | | | |
+-----------------+---------------+---------------+------------------+
| Yes | No | No | Boot with |
| | | | feature enabled |
+-----------------+---------------+---------------+------------------+
| Yes | Yes | No | Graceful boot |
| | | | failure |
+-----------------+---------------+---------------+------------------+
| Yes | Yes | Yes | Boot with |
| | | | feature enabled |
+-----------------+---------------+---------------+------------------+
More details in AMD64 APM[1] Vol 2: 15.34.10 SEV_STATUS MSR
[1] https://www.amd.com/system/files/TechDocs/40332.pdf
...@@ -14,13 +14,13 @@ endif ...@@ -14,13 +14,13 @@ endif
ifdef CONFIG_CC_IS_GCC ifdef CONFIG_CC_IS_GCC
RETPOLINE_CFLAGS := $(call cc-option,-mindirect-branch=thunk-extern -mindirect-branch-register) RETPOLINE_CFLAGS := $(call cc-option,-mindirect-branch=thunk-extern -mindirect-branch-register)
RETPOLINE_CFLAGS += $(call cc-option,-mindirect-branch-cs-prefix)
RETPOLINE_VDSO_CFLAGS := $(call cc-option,-mindirect-branch=thunk-inline -mindirect-branch-register) RETPOLINE_VDSO_CFLAGS := $(call cc-option,-mindirect-branch=thunk-inline -mindirect-branch-register)
endif endif
ifdef CONFIG_CC_IS_CLANG ifdef CONFIG_CC_IS_CLANG
RETPOLINE_CFLAGS := -mretpoline-external-thunk RETPOLINE_CFLAGS := -mretpoline-external-thunk
RETPOLINE_VDSO_CFLAGS := -mretpoline RETPOLINE_VDSO_CFLAGS := -mretpoline
endif endif
RETPOLINE_CFLAGS += $(call cc-option,-mindirect-branch-cs-prefix)
ifdef CONFIG_RETHUNK ifdef CONFIG_RETHUNK
RETHUNK_CFLAGS := -mfunction-return=thunk-extern RETHUNK_CFLAGS := -mfunction-return=thunk-extern
......
...@@ -180,6 +180,12 @@ void initialize_identity_maps(void *rmode) ...@@ -180,6 +180,12 @@ void initialize_identity_maps(void *rmode)
/* Load the new page-table. */ /* Load the new page-table. */
write_cr3(top_level_pgt); write_cr3(top_level_pgt);
/*
* Now that the required page table mappings are established and a
* GHCB can be used, check for SNP guest/HV feature compatibility.
*/
snp_check_features();
} }
static pte_t *split_large_pmd(struct x86_mapping_info *info, static pte_t *split_large_pmd(struct x86_mapping_info *info,
......
...@@ -126,6 +126,7 @@ static inline void console_init(void) ...@@ -126,6 +126,7 @@ static inline void console_init(void)
#ifdef CONFIG_AMD_MEM_ENCRYPT #ifdef CONFIG_AMD_MEM_ENCRYPT
void sev_enable(struct boot_params *bp); void sev_enable(struct boot_params *bp);
void snp_check_features(void);
void sev_es_shutdown_ghcb(void); void sev_es_shutdown_ghcb(void);
extern bool sev_es_check_ghcb_fault(unsigned long address); extern bool sev_es_check_ghcb_fault(unsigned long address);
void snp_set_page_private(unsigned long paddr); void snp_set_page_private(unsigned long paddr);
...@@ -143,6 +144,7 @@ static inline void sev_enable(struct boot_params *bp) ...@@ -143,6 +144,7 @@ static inline void sev_enable(struct boot_params *bp)
if (bp) if (bp)
bp->cc_blob_address = 0; bp->cc_blob_address = 0;
} }
static inline void snp_check_features(void) { }
static inline void sev_es_shutdown_ghcb(void) { } static inline void sev_es_shutdown_ghcb(void) { }
static inline bool sev_es_check_ghcb_fault(unsigned long address) static inline bool sev_es_check_ghcb_fault(unsigned long address)
{ {
......
...@@ -208,6 +208,23 @@ void sev_es_shutdown_ghcb(void) ...@@ -208,6 +208,23 @@ void sev_es_shutdown_ghcb(void)
error("Can't unmap GHCB page"); error("Can't unmap GHCB page");
} }
static void __noreturn sev_es_ghcb_terminate(struct ghcb *ghcb, unsigned int set,
unsigned int reason, u64 exit_info_2)
{
u64 exit_info_1 = SVM_VMGEXIT_TERM_REASON(set, reason);
vc_ghcb_invalidate(ghcb);
ghcb_set_sw_exit_code(ghcb, SVM_VMGEXIT_TERM_REQUEST);
ghcb_set_sw_exit_info_1(ghcb, exit_info_1);
ghcb_set_sw_exit_info_2(ghcb, exit_info_2);
sev_es_wr_ghcb_msr(__pa(ghcb));
VMGEXIT();
while (true)
asm volatile("hlt\n" : : : "memory");
}
bool sev_es_check_ghcb_fault(unsigned long address) bool sev_es_check_ghcb_fault(unsigned long address)
{ {
/* Check whether the fault was on the GHCB page */ /* Check whether the fault was on the GHCB page */
...@@ -270,6 +287,59 @@ static void enforce_vmpl0(void) ...@@ -270,6 +287,59 @@ static void enforce_vmpl0(void)
sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_NOT_VMPL0); sev_es_terminate(SEV_TERM_SET_LINUX, GHCB_TERM_NOT_VMPL0);
} }
/*
* SNP_FEATURES_IMPL_REQ is the mask of SNP features that will need
* guest side implementation for proper functioning of the guest. If any
* of these features are enabled in the hypervisor but are lacking guest
* side implementation, the behavior of the guest will be undefined. The
* guest could fail in non-obvious way making it difficult to debug.
*
* As the behavior of reserved feature bits is unknown to be on the
* safe side add them to the required features mask.
*/
#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_DEBUG_SWAP | \
MSR_AMD64_SNP_VMPL_SSS | \
MSR_AMD64_SNP_SECURE_TSC | \
MSR_AMD64_SNP_VMGEXIT_PARAM | \
MSR_AMD64_SNP_VMSA_REG_PROTECTION | \
MSR_AMD64_SNP_RESERVED_BIT13 | \
MSR_AMD64_SNP_RESERVED_BIT15 | \
MSR_AMD64_SNP_RESERVED_MASK)
/*
* SNP_FEATURES_PRESENT is the mask of SNP features that are implemented
* by the guest kernel. As and when a new feature is implemented in the
* guest kernel, a corresponding bit should be added to the mask.
*/
#define SNP_FEATURES_PRESENT (0)
void snp_check_features(void)
{
u64 unsupported;
if (!(sev_status & MSR_AMD64_SEV_SNP_ENABLED))
return;
/*
* Terminate the boot if hypervisor has enabled any feature lacking
* guest side implementation. Pass on the unsupported features mask through
* EXIT_INFO_2 of the GHCB protocol so that those features can be reported
* as part of the guest boot failure.
*/
unsupported = sev_status & SNP_FEATURES_IMPL_REQ & ~SNP_FEATURES_PRESENT;
if (unsupported) {
if (ghcb_version < 2 || (!boot_ghcb && !early_setup_ghcb()))
sev_es_terminate(SEV_TERM_SET_GEN, GHCB_SNP_UNSUPPORTED);
sev_es_ghcb_terminate(boot_ghcb, SEV_TERM_SET_GEN,
GHCB_SNP_UNSUPPORTED, unsupported);
}
}
void sev_enable(struct boot_params *bp) void sev_enable(struct boot_params *bp)
{ {
unsigned int eax, ebx, ecx, edx; unsigned int eax, ebx, ecx, edx;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <asm/mmu.h> #include <asm/mmu.h>
#include <asm/mpspec.h> #include <asm/mpspec.h>
#include <asm/x86_init.h> #include <asm/x86_init.h>
#include <asm/cpufeature.h>
#ifdef CONFIG_ACPI_APEI #ifdef CONFIG_ACPI_APEI
# include <asm/pgtable_types.h> # include <asm/pgtable_types.h>
...@@ -63,6 +64,13 @@ extern int (*acpi_suspend_lowlevel)(void); ...@@ -63,6 +64,13 @@ extern int (*acpi_suspend_lowlevel)(void);
/* Physical address to resume after wakeup */ /* Physical address to resume after wakeup */
unsigned long acpi_get_wakeup_address(void); unsigned long acpi_get_wakeup_address(void);
static inline bool acpi_skip_set_wakeup_address(void)
{
return cpu_feature_enabled(X86_FEATURE_XENPV);
}
#define acpi_skip_set_wakeup_address acpi_skip_set_wakeup_address
/* /*
* Check if the CPU can handle C2 and deeper * Check if the CPU can handle C2 and deeper
*/ */
......
...@@ -566,6 +566,26 @@ ...@@ -566,6 +566,26 @@
#define MSR_AMD64_SEV_ES_ENABLED BIT_ULL(MSR_AMD64_SEV_ES_ENABLED_BIT) #define MSR_AMD64_SEV_ES_ENABLED BIT_ULL(MSR_AMD64_SEV_ES_ENABLED_BIT)
#define MSR_AMD64_SEV_SNP_ENABLED BIT_ULL(MSR_AMD64_SEV_SNP_ENABLED_BIT) #define MSR_AMD64_SEV_SNP_ENABLED BIT_ULL(MSR_AMD64_SEV_SNP_ENABLED_BIT)
/* SNP feature bits enabled by the hypervisor */
#define MSR_AMD64_SNP_VTOM BIT_ULL(3)
#define MSR_AMD64_SNP_REFLECT_VC BIT_ULL(4)
#define MSR_AMD64_SNP_RESTRICTED_INJ BIT_ULL(5)
#define MSR_AMD64_SNP_ALT_INJ BIT_ULL(6)
#define MSR_AMD64_SNP_DEBUG_SWAP BIT_ULL(7)
#define MSR_AMD64_SNP_PREVENT_HOST_IBS BIT_ULL(8)
#define MSR_AMD64_SNP_BTB_ISOLATION BIT_ULL(9)
#define MSR_AMD64_SNP_VMPL_SSS BIT_ULL(10)
#define MSR_AMD64_SNP_SECURE_TSC BIT_ULL(11)
#define MSR_AMD64_SNP_VMGEXIT_PARAM BIT_ULL(12)
#define MSR_AMD64_SNP_IBS_VIRT BIT_ULL(14)
#define MSR_AMD64_SNP_VMSA_REG_PROTECTION BIT_ULL(16)
#define MSR_AMD64_SNP_SMT_PROTECTION BIT_ULL(17)
/* SNP feature bits reserved for future use. */
#define MSR_AMD64_SNP_RESERVED_BIT13 BIT_ULL(13)
#define MSR_AMD64_SNP_RESERVED_BIT15 BIT_ULL(15)
#define MSR_AMD64_SNP_RESERVED_MASK GENMASK_ULL(63, 18)
#define MSR_AMD64_VIRT_SPEC_CTRL 0xc001011f #define MSR_AMD64_VIRT_SPEC_CTRL 0xc001011f
/* AMD Collaborative Processor Performance Control MSRs */ /* AMD Collaborative Processor Performance Control MSRs */
......
...@@ -116,6 +116,12 @@ ...@@ -116,6 +116,12 @@
#define SVM_VMGEXIT_AP_CREATE 1 #define SVM_VMGEXIT_AP_CREATE 1
#define SVM_VMGEXIT_AP_DESTROY 2 #define SVM_VMGEXIT_AP_DESTROY 2
#define SVM_VMGEXIT_HV_FEATURES 0x8000fffd #define SVM_VMGEXIT_HV_FEATURES 0x8000fffd
#define SVM_VMGEXIT_TERM_REQUEST 0x8000fffe
#define SVM_VMGEXIT_TERM_REASON(reason_set, reason_code) \
/* SW_EXITINFO1[3:0] */ \
(((((u64)reason_set) & 0xf)) | \
/* SW_EXITINFO1[11:4] */ \
((((u64)reason_code) & 0xff) << 4))
#define SVM_VMGEXIT_UNSUPPORTED_EVENT 0x8000ffff #define SVM_VMGEXIT_UNSUPPORTED_EVENT 0x8000ffff
/* Exit code reserved for hypervisor/software use */ /* Exit code reserved for hypervisor/software use */
......
...@@ -114,6 +114,7 @@ static void make_8259A_irq(unsigned int irq) ...@@ -114,6 +114,7 @@ static void make_8259A_irq(unsigned int irq)
disable_irq_nosync(irq); disable_irq_nosync(irq);
io_apic_irqs &= ~(1<<irq); io_apic_irqs &= ~(1<<irq);
irq_set_chip_and_handler(irq, &i8259A_chip, handle_level_irq); irq_set_chip_and_handler(irq, &i8259A_chip, handle_level_irq);
irq_set_status_flags(irq, IRQ_LEVEL);
enable_irq(irq); enable_irq(irq);
lapic_assign_legacy_vector(irq, true); lapic_assign_legacy_vector(irq, true);
} }
......
...@@ -65,8 +65,10 @@ void __init init_ISA_irqs(void) ...@@ -65,8 +65,10 @@ void __init init_ISA_irqs(void)
legacy_pic->init(0); legacy_pic->init(0);
for (i = 0; i < nr_legacy_irqs(); i++) for (i = 0; i < nr_legacy_irqs(); i++) {
irq_set_chip_and_handler(i, chip, handle_level_irq); irq_set_chip_and_handler(i, chip, handle_level_irq);
irq_set_status_flags(i, IRQ_LEVEL);
}
} }
void __init init_IRQ(void) void __init init_IRQ(void)
......
...@@ -392,6 +392,7 @@ static void xen_teardown_msi_irqs(struct pci_dev *dev) ...@@ -392,6 +392,7 @@ static void xen_teardown_msi_irqs(struct pci_dev *dev)
msi_for_each_desc(msidesc, &dev->dev, MSI_DESC_ASSOCIATED) { msi_for_each_desc(msidesc, &dev->dev, MSI_DESC_ASSOCIATED) {
for (i = 0; i < msidesc->nvec_used; i++) for (i = 0; i < msidesc->nvec_used; i++)
xen_destroy_irq(msidesc->irq + i); xen_destroy_irq(msidesc->irq + i);
msidesc->irq = 0;
} }
} }
...@@ -433,6 +434,7 @@ static struct msi_domain_ops xen_pci_msi_domain_ops = { ...@@ -433,6 +434,7 @@ static struct msi_domain_ops xen_pci_msi_domain_ops = {
}; };
static struct msi_domain_info xen_pci_msi_domain_info = { static struct msi_domain_info xen_pci_msi_domain_info = {
.flags = MSI_FLAG_PCI_MSIX | MSI_FLAG_FREE_MSI_DESCS | MSI_FLAG_DEV_SYSFS,
.ops = &xen_pci_msi_domain_ops, .ops = &xen_pci_msi_domain_ops,
}; };
......
...@@ -60,13 +60,17 @@ static struct notifier_block tts_notifier = { ...@@ -60,13 +60,17 @@ static struct notifier_block tts_notifier = {
.priority = 0, .priority = 0,
}; };
#ifndef acpi_skip_set_wakeup_address
#define acpi_skip_set_wakeup_address() false
#endif
static int acpi_sleep_prepare(u32 acpi_state) static int acpi_sleep_prepare(u32 acpi_state)
{ {
#ifdef CONFIG_ACPI_SLEEP #ifdef CONFIG_ACPI_SLEEP
unsigned long acpi_wakeup_address; unsigned long acpi_wakeup_address;
/* do we have a wakeup address for S2 and S3? */ /* do we have a wakeup address for S2 and S3? */
if (acpi_state == ACPI_STATE_S3) { if (acpi_state == ACPI_STATE_S3 && !acpi_skip_set_wakeup_address()) {
acpi_wakeup_address = acpi_get_wakeup_address(); acpi_wakeup_address = acpi_get_wakeup_address();
if (!acpi_wakeup_address) if (!acpi_wakeup_address)
return -EFAULT; return -EFAULT;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment