Commit cda846f1 authored by Jarkko Sakkinen's avatar Jarkko Sakkinen Committed by H. Peter Anvin

x86, realmode: read cr4 and EFER from kernel for 64-bit trampoline

This patch changes 64-bit trampoline so that CR4 and
EFER are provided by the kernel instead of using fixed
values.
Signed-off-by: default avatarJarkko Sakkinen <jarkko.sakkinen@intel.com>
Link: http://lkml.kernel.org/r/1336501366-28617-24-git-send-email-jarkko.sakkinen@intel.comSigned-off-by: default avatarH. Peter Anvin <hpa@linux.intel.com>
parent bf8b88e9
...@@ -544,13 +544,16 @@ static inline void load_sp0(struct tss_struct *tss, ...@@ -544,13 +544,16 @@ static inline void load_sp0(struct tss_struct *tss,
* enable), so that any CPU's that boot up * enable), so that any CPU's that boot up
* after us can get the correct flags. * 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) static inline void set_in_cr4(unsigned long mask)
{ {
unsigned long cr4; unsigned long cr4;
mmu_cr4_features |= mask; mmu_cr4_features |= mask;
if (trampoline_cr4_features)
*trampoline_cr4_features = mmu_cr4_features;
cr4 = read_cr4(); cr4 = read_cr4();
cr4 |= mask; cr4 |= mask;
write_cr4(cr4); write_cr4(cr4);
...@@ -561,6 +564,8 @@ static inline void clear_in_cr4(unsigned long mask) ...@@ -561,6 +564,8 @@ static inline void clear_in_cr4(unsigned long mask)
unsigned long cr4; unsigned long cr4;
mmu_cr4_features &= ~mask; mmu_cr4_features &= ~mask;
if (trampoline_cr4_features)
*trampoline_cr4_features = mmu_cr4_features;
cr4 = read_cr4(); cr4 = read_cr4();
cr4 &= ~mask; cr4 &= ~mask;
write_cr4(cr4); write_cr4(cr4);
......
...@@ -24,18 +24,22 @@ struct real_mode_header { ...@@ -24,18 +24,22 @@ struct real_mode_header {
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
u32 machine_real_restart_asm; u32 machine_real_restart_asm;
#endif #endif
} __attribute__((__packed__)); };
/* This must match data at trampoline_32/64.S */ /* This must match data at trampoline_32/64.S */
struct trampoline_header { struct trampoline_header {
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
u32 start; u32 start;
u16 gdt_pad;
u16 gdt_limit; u16 gdt_limit;
u32 gdt_base; u32 gdt_base;
#else #else
u64 start; u64 start;
u32 cr4;
u32 efer_low;
u32 efer_high;
#endif #endif
} __attribute__((__packed__)); };
extern struct real_mode_header *real_mode_header; extern struct real_mode_header *real_mode_header;
extern unsigned char real_mode_blob_end[]; extern unsigned char real_mode_blob_end[];
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <asm/realmode.h> #include <asm/realmode.h>
struct real_mode_header *real_mode_header; struct real_mode_header *real_mode_header;
u32 *trampoline_cr4_features;
void __init setup_real_mode(void) void __init setup_real_mode(void)
{ {
...@@ -64,7 +65,14 @@ 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_limit = __BOOT_DS + 7;
trampoline_header->gdt_base = __pa(boot_gdt); trampoline_header->gdt_base = __pa(boot_gdt);
#else #else
if (rdmsr_safe(MSR_EFER, &trampoline_header->efer_low,
&trampoline_header->efer_high))
BUG();
trampoline_header->start = (u64) secondary_startup_64; 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 = (u64 *) __va(real_mode_header->trampoline_pgd);
trampoline_pgd[0] = __pa(level3_ident_pgt) + _KERNPG_TABLE; trampoline_pgd[0] = __pa(level3_ident_pgt) + _KERNPG_TABLE;
trampoline_pgd[511] = __pa(level3_kernel_pgt) + _KERNPG_TABLE; trampoline_pgd[511] = __pa(level3_kernel_pgt) + _KERNPG_TABLE;
......
...@@ -975,6 +975,8 @@ void __init setup_arch(char **cmdline_p) ...@@ -975,6 +975,8 @@ void __init setup_arch(char **cmdline_p)
if (boot_cpu_data.cpuid_level >= 0) { if (boot_cpu_data.cpuid_level >= 0) {
/* A CPU has %cr4 if and only if it has CPUID */ /* A CPU has %cr4 if and only if it has CPUID */
mmu_cr4_features = read_cr4(); mmu_cr4_features = read_cr4();
if (trampoline_cr4_features)
*trampoline_cr4_features = mmu_cr4_features;
} }
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
.section ".header", "a" .section ".header", "a"
.balign 16
GLOBAL(real_mode_header) GLOBAL(real_mode_header)
.long pa_text_start .long pa_text_start
.long pa_ro_end .long pa_ro_end
......
...@@ -34,9 +34,9 @@ ...@@ -34,9 +34,9 @@
#include "realmode.h" #include "realmode.h"
.text .text
.balign PAGE_SIZE
.code16 .code16
.balign PAGE_SIZE
ENTRY(trampoline_start) ENTRY(trampoline_start)
cli # We should be safe anyway cli # We should be safe anyway
wbinvd wbinvd
...@@ -65,8 +65,8 @@ ENTRY(trampoline_start) ...@@ -65,8 +65,8 @@ ENTRY(trampoline_start)
* to 32 bit. * to 32 bit.
*/ */
lidtl tidt # load idt with 0, 0 lidtl tr_idt # load idt with 0, 0
lgdtl tgdt # load gdt with whatever is appropriate lgdtl tr_gdt # load gdt with whatever is appropriate
movw $__KERNEL_DS, %dx # Data segment descriptor movw $__KERNEL_DS, %dx # Data segment descriptor
...@@ -93,16 +93,17 @@ ENTRY(startup_32) ...@@ -93,16 +93,17 @@ ENTRY(startup_32)
movl %edx, %fs movl %edx, %fs
movl %edx, %gs movl %edx, %gs
movl $X86_CR4_PAE, %eax movl pa_tr_cr4, %eax
movl %eax, %cr4 # Enable PAE mode movl %eax, %cr4 # Enable PAE mode
# Setup trampoline 4 level pagetables # Setup trampoline 4 level pagetables
movl $pa_trampoline_pgd, %eax movl $pa_trampoline_pgd, %eax
movl %eax, %cr3 movl %eax, %cr3
# Set up EFER
movl pa_tr_efer, %eax
movl pa_tr_efer + 4, %edx
movl $MSR_EFER, %ecx movl $MSR_EFER, %ecx
movl $((1 << _EFER_LME) | (1 << _EFER_NX)), %eax # Enable Long Mode
xorl %edx, %edx
wrmsr wrmsr
# Enable paging and in turn activate Long Mode # Enable paging and in turn activate Long Mode
...@@ -124,23 +125,4 @@ ENTRY(startup_64) ...@@ -124,23 +125,4 @@ ENTRY(startup_64)
# Now jump into the kernel using virtual addresses # Now jump into the kernel using virtual addresses
jmpq *tr_start(%rip) 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" #include "trampoline_common.S"
.section ".rodata","a" .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 .balign 4
tr_idt: .fill 1, 6, 0 tr_idt: .fill 1, 6, 0
...@@ -8,12 +23,16 @@ tr_idt: .fill 1, 6, 0 ...@@ -8,12 +23,16 @@ tr_idt: .fill 1, 6, 0
.balign 4 .balign 4
GLOBAL(trampoline_status) .space 4 GLOBAL(trampoline_status) .space 4
.balign 8
GLOBAL(trampoline_header) GLOBAL(trampoline_header)
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
tr_start: .space 4 tr_start: .space 4
tr_gdt_pad: .space 2
tr_gdt: .space 6 tr_gdt: .space 6
#else #else
tr_start: .space 8 tr_start: .space 8
GLOBAL(tr_cr4) .space 4
GLOBAL(tr_efer) .space 8
#endif #endif
END(trampoline_header) END(trampoline_header)
......
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