x86, realmode: read cr4 and EFER from kernel for 64-bit trampoline
authorJarkko Sakkinen <jarkko.sakkinen@intel.com>
Tue, 8 May 2012 18:22:46 +0000 (21:22 +0300)
committerH. Peter Anvin <hpa@linux.intel.com>
Tue, 8 May 2012 22:04:27 +0000 (15:04 -0700)
This patch changes 64-bit trampoline so that CR4 and
EFER are provided by the kernel instead of using fixed
values.

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@intel.com>
Link: http://lkml.kernel.org/r/1336501366-28617-24-git-send-email-jarkko.sakkinen@intel.com
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
arch/x86/include/asm/processor.h
arch/x86/include/asm/realmode.h
arch/x86/kernel/realmode.c
arch/x86/kernel/setup.c
arch/x86/realmode/rm/header.S
arch/x86/realmode/rm/trampoline_64.S
arch/x86/realmode/rm/trampoline_common.S

index 4fa7dcceb6c084816346562bacdac4aa7098a9ee..404583ccf0cfa1ddfe58057041008132f5c1f914 100644 (file)
@@ -544,13 +544,16 @@ static inline void load_sp0(struct tss_struct *tss,
  * enable), so that any CPU's that boot up
  * after us can get the correct flags.
  */
-extern unsigned long           mmu_cr4_features;
+extern unsigned long mmu_cr4_features;
+extern u32 *trampoline_cr4_features;
 
 static inline void set_in_cr4(unsigned long mask)
 {
        unsigned long cr4;
 
        mmu_cr4_features |= mask;
+       if (trampoline_cr4_features)
+               *trampoline_cr4_features = mmu_cr4_features;
        cr4 = read_cr4();
        cr4 |= mask;
        write_cr4(cr4);
@@ -561,6 +564,8 @@ static inline void clear_in_cr4(unsigned long mask)
        unsigned long cr4;
 
        mmu_cr4_features &= ~mask;
+       if (trampoline_cr4_features)
+               *trampoline_cr4_features = mmu_cr4_features;
        cr4 = read_cr4();
        cr4 &= ~mask;
        write_cr4(cr4);
index 1421eed1c8e8586eff49fec7fd9aab7001cb6be8..937dc6071d765762dba5b0ced982112ad95f4cad 100644 (file)
@@ -24,18 +24,22 @@ struct real_mode_header {
 #ifdef CONFIG_X86_32
        u32     machine_real_restart_asm;
 #endif
-} __attribute__((__packed__));
+};
 
 /* This must match data at trampoline_32/64.S */
 struct trampoline_header {
 #ifdef CONFIG_X86_32
        u32 start;
+       u16 gdt_pad;
        u16 gdt_limit;
        u32 gdt_base;
 #else
        u64 start;
+       u32 cr4;
+       u32 efer_low;
+       u32 efer_high;
 #endif
-} __attribute__((__packed__));
+};
 
 extern struct real_mode_header *real_mode_header;
 extern unsigned char real_mode_blob_end[];
index 712fba8fd7743c026458bed4662a41f1cdb21d9e..66ac276cf361eafabbef2dd82ae8ea42c9125354 100644 (file)
@@ -6,6 +6,7 @@
 #include <asm/realmode.h>
 
 struct real_mode_header *real_mode_header;
+u32 *trampoline_cr4_features;
 
 void __init setup_real_mode(void)
 {
@@ -64,7 +65,14 @@ void __init setup_real_mode(void)
        trampoline_header->gdt_limit = __BOOT_DS + 7;
        trampoline_header->gdt_base = __pa(boot_gdt);
 #else
+       if (rdmsr_safe(MSR_EFER, &trampoline_header->efer_low,
+                      &trampoline_header->efer_high))
+               BUG();
+
        trampoline_header->start = (u64) secondary_startup_64;
+       trampoline_cr4_features = &trampoline_header->cr4;
+       *trampoline_cr4_features = read_cr4();
+
        trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd);
        trampoline_pgd[0] = __pa(level3_ident_pgt) + _KERNPG_TABLE;
        trampoline_pgd[511] = __pa(level3_kernel_pgt) + _KERNPG_TABLE;
index 7a14fece9cfc64f957195cf9e1878ae45d9bd8fa..efcf305210a437b061a5415aae0c48395275a152 100644 (file)
@@ -975,6 +975,8 @@ void __init setup_arch(char **cmdline_p)
        if (boot_cpu_data.cpuid_level >= 0) {
                /* A CPU has %cr4 if and only if it has CPUID */
                mmu_cr4_features = read_cr4();
+               if (trampoline_cr4_features)
+                       *trampoline_cr4_features = mmu_cr4_features;
        }
 
 #ifdef CONFIG_X86_32
index b4c32632bf1684c05d4c9046593731f38024c487..4612d5382791e903e0ec1f5b06a743b1148a99bc 100644 (file)
@@ -9,6 +9,7 @@
 
        .section ".header", "a"
 
+       .balign 16
 GLOBAL(real_mode_header)
        .long   pa_text_start
        .long   pa_ro_end
index 3f7293239365acc549d7ffd6594cd13ccf7c6a5e..66e26f088288305299781f2fe38d11f8d3f331ae 100644 (file)
@@ -34,9 +34,9 @@
 #include "realmode.h"
 
        .text
-       .balign PAGE_SIZE
        .code16
 
+       .balign PAGE_SIZE
 ENTRY(trampoline_start)
        cli                     # We should be safe anyway
        wbinvd
@@ -65,8 +65,8 @@ ENTRY(trampoline_start)
         * to 32 bit.
         */
 
-       lidtl   tidt    # load idt with 0, 0
-       lgdtl   tgdt    # load gdt with whatever is appropriate
+       lidtl   tr_idt  # load idt with 0, 0
+       lgdtl   tr_gdt  # load gdt with whatever is appropriate
 
        movw    $__KERNEL_DS, %dx       # Data segment descriptor
 
@@ -93,16 +93,17 @@ ENTRY(startup_32)
        movl    %edx, %fs
        movl    %edx, %gs
 
-       movl    $X86_CR4_PAE, %eax
+       movl    pa_tr_cr4, %eax
        movl    %eax, %cr4              # Enable PAE mode
 
        # Setup trampoline 4 level pagetables
        movl    $pa_trampoline_pgd, %eax
        movl    %eax, %cr3
 
+       # Set up EFER
+       movl    pa_tr_efer, %eax
+       movl    pa_tr_efer + 4, %edx
        movl    $MSR_EFER, %ecx
-       movl    $((1 << _EFER_LME) | (1 << _EFER_NX)), %eax     # Enable Long Mode
-       xorl    %edx, %edx
        wrmsr
 
        # Enable paging and in turn activate Long Mode
@@ -124,23 +125,4 @@ ENTRY(startup_64)
        # Now jump into the kernel using virtual addresses
        jmpq    *tr_start(%rip)
 
-       .section ".rodata","a"
-       .balign 16
-tidt:
-       .word   0                       # idt limit = 0
-       .word   0, 0                    # idt base = 0L
-
-       # Duplicate the global descriptor table
-       # so the kernel can live anywhere
-       .balign 16
-       .globl tgdt
-tgdt:
-       .short  tgdt_end - tgdt - 1     # gdt limit
-       .long   pa_tgdt
-       .short  0
-       .quad   0x00cf9b000000ffff      # __KERNEL32_CS
-       .quad   0x00af9b000000ffff      # __KERNEL_CS
-       .quad   0x00cf93000000ffff      # __KERNEL_DS
-tgdt_end:
-
 #include "trampoline_common.S"
index c3f951c468c5b98b9c06a5aafd322001b6dbf290..cac444b942f8689427d7f288600adf2526bba885 100644 (file)
@@ -1,5 +1,20 @@
        .section ".rodata","a"
 
+#ifdef CONFIG_X86_64
+       # Duplicate the global descriptor table
+       # so the kernel can live anywhere
+       .balign 16
+       .globl tr_gdt
+tr_gdt:
+       .short  tr_gdt_end - tr_gdt - 1 # gdt limit
+       .long   pa_tr_gdt
+       .short  0
+       .quad   0x00cf9b000000ffff      # __KERNEL32_CS
+       .quad   0x00af9b000000ffff      # __KERNEL_CS
+       .quad   0x00cf93000000ffff      # __KERNEL_DS
+tr_gdt_end:
+#endif
+
        .balign 4
 tr_idt: .fill 1, 6, 0
 
@@ -8,12 +23,16 @@ tr_idt: .fill 1, 6, 0
        .balign 4
 GLOBAL(trampoline_status)      .space  4
 
+       .balign 8
 GLOBAL(trampoline_header)
 #ifdef CONFIG_X86_32
        tr_start:               .space  4
+       tr_gdt_pad:             .space  2
        tr_gdt:                 .space  6
 #else
        tr_start:               .space  8
+       GLOBAL(tr_cr4)          .space  4
+       GLOBAL(tr_efer)         .space  8
 #endif
 END(trampoline_header)