[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] xen: Move NX handling to a dedicated place



Currently the CONFIG_REQUIRE_NX prevents booting XEN, if NX is disabled
in the BIOS. AMD doesn't have a software-accessible MSR to re-enable it,
so there is nothing we can do. The system is going to die anyway. But on
Intel NX might just be hidden via IA32_MISC_ENABLE.XD_DISABLE. But the
function to re-enable it is called after the check + panic in
efi_arch_cpu. So, this patch removes the early check and moves the
entire NX handling into a dedicated place.

Signed-off-by: Julian Vetter <julian.vetter@xxxxxxxxxx>
---
 xen/arch/x86/boot/head.S         | 56 --------------------------------
 xen/arch/x86/boot/trampoline.S   |  5 ++-
 xen/arch/x86/cpu/intel.c         |  4 ---
 xen/arch/x86/efi/efi-boot.h      | 12 -------
 xen/arch/x86/include/asm/setup.h |  2 ++
 xen/arch/x86/setup.c             | 46 ++++++++++++++++++++++++++
 6 files changed, 50 insertions(+), 75 deletions(-)

diff --git a/xen/arch/x86/boot/head.S b/xen/arch/x86/boot/head.S
index 77bb7a9e21..7fb7fb1351 100644
--- a/xen/arch/x86/boot/head.S
+++ b/xen/arch/x86/boot/head.S
@@ -133,7 +133,6 @@ multiboot2_header:
 .Lbad_ldr_nbs: .asciz "ERR: Bootloader shutdown EFI x64 boot services!"
 .Lbad_efi_msg: .asciz "ERR: EFI IA-32 platforms are not supported!"
 .Lbag_alg_msg: .asciz "ERR: Xen must be loaded at a 2Mb boundary!"
-.Lno_nx_msg:   .asciz "ERR: Not an NX-capable CPU!"
 
         .section .init.data, "aw", @progbits
         .subsection 1 /* Put data here after the page tables (in x86_64.S). */
@@ -165,11 +164,6 @@ early_error: /* Here to improve the disassembly. */
 .Lnot_aligned:
         mov     $sym_offs(.Lbag_alg_msg), %ecx
         jmp     .Lget_vtb
-#ifdef CONFIG_REQUIRE_NX
-.Lno_nx:
-        mov     $sym_offs(.Lno_nx_msg), %ecx
-        jmp     .Lget_vtb
-#endif
 .Lmb2_no_bs:
         /*
          * Ditto. Additionally, here there is a chance that Xen was started
@@ -547,56 +541,6 @@ trampoline_setup:
         bt      $cpufeat_bit(X86_FEATURE_LM),%edx
         jnc     .Lbad_cpu
 
-        /*
-         * Check for NX
-         *   - If Xen was compiled requiring it simply assert it's
-         *     supported. The trampoline already has the right constant.
-         *   - Otherwise, update the trampoline EFER mask accordingly.
-         */
-        bt      $cpufeat_bit(X86_FEATURE_NX), %edx
-        jc     .Lgot_nx
-
-        /*
-         * NX appears to be unsupported, but it might be hidden.
-         *
-         * The feature is part of the AMD64 spec, but the very first Intel
-         * 64bit CPUs lacked the feature, and thereafter there was a
-         * firmware knob to disable the feature. Undo the disable if
-         * possible.
-         *
-         * All 64bit Intel CPUs support this MSR. If virtualised, expect
-         * the hypervisor to either emulate the MSR or give us NX.
-         */
-        xor     %eax, %eax
-        cpuid
-        cmp     $X86_VENDOR_INTEL_EBX, %ebx
-        jnz     .Lno_nx
-        cmp     $X86_VENDOR_INTEL_EDX, %edx
-        jnz     .Lno_nx
-        cmp     $X86_VENDOR_INTEL_ECX, %ecx
-        jnz     .Lno_nx
-
-        /* Clear the XD_DISABLE bit */
-        mov     $MSR_IA32_MISC_ENABLE, %ecx
-        rdmsr
-        btr     $2, %edx
-        jnc     .Lno_nx
-        wrmsr
-        orb     $MSR_IA32_MISC_ENABLE_XD_DISABLE >> 32, 4 + 
sym_esi(trampoline_misc_enable_off)
-
-        /* Check again for NX */
-        mov     $0x80000001, %eax
-        cpuid
-        bt      $cpufeat_bit(X86_FEATURE_NX), %edx
-        jnc     .Lno_nx
-
-.Lgot_nx:
-#ifndef CONFIG_REQUIRE_NX
-        /* Adjust EFER given that NX is present */
-        orb     $EFER_NXE >> 8, 1 + sym_esi(trampoline_efer)
-.Lno_nx:
-#endif
-
         /* Stash TSC to calculate a good approximation of time-since-boot */
         rdtsc
         mov     %eax,     sym_esi(boot_tsc_stamp)
diff --git a/xen/arch/x86/boot/trampoline.S b/xen/arch/x86/boot/trampoline.S
index a92e399fbe..8e8d50cbdf 100644
--- a/xen/arch/x86/boot/trampoline.S
+++ b/xen/arch/x86/boot/trampoline.S
@@ -144,10 +144,9 @@ gdt_48:
 GLOBAL(trampoline_misc_enable_off)
         .quad   0
 
-/* EFER OR-mask for boot paths.  SCE conditional on PV support, NX added when 
available. */
+/* EFER OR-mask for boot paths.  SCE conditional on PV support. */
 GLOBAL(trampoline_efer)
-        .long   EFER_LME | (EFER_SCE * IS_ENABLED(CONFIG_PV)) | \
-                (EFER_NXE * IS_ENABLED(CONFIG_REQUIRE_NX))
+        .long   EFER_LME | (EFER_SCE * IS_ENABLED(CONFIG_PV))
 
 GLOBAL(trampoline_xen_phys_start)
         .long   0
diff --git a/xen/arch/x86/cpu/intel.c b/xen/arch/x86/cpu/intel.c
index b76797cb9a..e8cf51e853 100644
--- a/xen/arch/x86/cpu/intel.c
+++ b/xen/arch/x86/cpu/intel.c
@@ -351,10 +351,6 @@ static void cf_check early_init_intel(struct cpuinfo_x86 
*c)
        if (c->x86 == 15 && c->x86_cache_alignment == 64)
                c->x86_cache_alignment = 128;
 
-       if (c == &boot_cpu_data &&
-           bootsym(trampoline_misc_enable_off) & 
MSR_IA32_MISC_ENABLE_XD_DISABLE)
-               printk(KERN_INFO "re-enabled NX (Execute Disable) 
protection\n");
-
        intel_unlock_cpuid_leaves(c);
 
        /* CPUID workaround for Intel 0F33/0F34 CPU */
diff --git a/xen/arch/x86/efi/efi-boot.h b/xen/arch/x86/efi/efi-boot.h
index 0194720003..8dfd549f12 100644
--- a/xen/arch/x86/efi/efi-boot.h
+++ b/xen/arch/x86/efi/efi-boot.h
@@ -748,18 +748,6 @@ static void __init efi_arch_cpu(void)
     if ( (eax >> 16) == 0x8000 && eax > 0x80000000U )
     {
         caps[FEATURESET_e1d] = cpuid_edx(0x80000001U);
-
-        /*
-         * This check purposefully doesn't use cpu_has_nx because
-         * cpu_has_nx bypasses the boot_cpu_data read if Xen was compiled
-         * with CONFIG_REQUIRE_NX
-         */
-        if ( IS_ENABLED(CONFIG_REQUIRE_NX) &&
-             !boot_cpu_has(X86_FEATURE_NX) )
-            blexit(L"This build of Xen requires NX support");
-
-        if ( cpu_has_nx )
-            trampoline_efer |= EFER_NXE;
     }
 }
 
diff --git a/xen/arch/x86/include/asm/setup.h b/xen/arch/x86/include/asm/setup.h
index b01e83a8ed..16f53725ca 100644
--- a/xen/arch/x86/include/asm/setup.h
+++ b/xen/arch/x86/include/asm/setup.h
@@ -70,4 +70,6 @@ extern bool opt_dom0_msr_relaxed;
 
 #define max_init_domid (0)
 
+void nx_init(void);
+
 #endif
diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
index 27c63d1d97..608720b717 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -1119,6 +1119,50 @@ static struct domain *__init create_dom0(struct 
boot_info *bi)
     return d;
 }
 
+void __init nx_init(void)
+{
+    uint64_t misc_enable;
+    uint32_t eax, ebx, ecx, edx;
+
+    if ( !boot_cpu_has(X86_FEATURE_NX) )
+    {
+        /* Intel: try to unhide NX by clearing XD_DISABLE */
+        cpuid(0, &eax, &ebx, &ecx, &edx);
+        if ( ebx == X86_VENDOR_INTEL_EBX &&
+             ecx == X86_VENDOR_INTEL_ECX &&
+             edx == X86_VENDOR_INTEL_EDX )
+        {
+            rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
+            if ( misc_enable & MSR_IA32_MISC_ENABLE_XD_DISABLE )
+            {
+                misc_enable &= ~MSR_IA32_MISC_ENABLE_XD_DISABLE;
+                wrmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
+
+                /* Re-read CPUID after having cleared XD_DISABLE */
+                boot_cpu_data.x86_capability[FEATURESET_e1d] = 
cpuid_edx(0x80000001U);
+
+                /* Adjust misc_enable_off for secondary startup and wakeup 
code */
+                bootsym(trampoline_misc_enable_off) |= 
MSR_IA32_MISC_ENABLE_XD_DISABLE;
+                printk(KERN_INFO "re-enabled NX (Execute Disable) 
protection\n");
+            }
+        }
+        /* AMD: nothing we can do - NX must be enabled in BIOS */
+    }
+
+    /* Enable EFER.NXE only if NX is available */
+    if ( boot_cpu_has(X86_FEATURE_NX) )
+    {
+        if ( !(read_efer() & EFER_NXE) )
+            write_efer(read_efer() | EFER_NXE);
+
+        /* Adjust trampoline_efer for secondary startup and wakeup code */
+        bootsym(trampoline_efer) |= EFER_NXE;
+    }
+
+    if ( IS_ENABLED(CONFIG_REQUIRE_NX) && !boot_cpu_has(X86_FEATURE_NX) )
+        panic("This build of Xen requires NX support\n");
+}
+
 /* How much of the directmap is prebuilt at compile time. */
 #define PREBUILT_MAP_LIMIT (1 << L2_PAGETABLE_SHIFT)
 
@@ -1159,6 +1203,8 @@ void asmlinkage __init noreturn __start_xen(void)
     rdmsrl(MSR_EFER, this_cpu(efer));
     asm volatile ( "mov %%cr4,%0" : "=r" (info->cr4) );
 
+    nx_init();
+
     /* Enable NMIs.  Our loader (e.g. Tboot) may have left them disabled. */
     enable_nmis();
 
-- 
2.51.0



--
Julian Vetter | Vates Hypervisor & Kernel Developer

XCP-ng & Xen Orchestra - Vates solutions

web: https://vates.tech




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.