diff options
author | Jarkko Sakkinen <jarkko.sakkinen@intel.com> | 2012-05-08 14:22:46 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2012-05-08 18:04:27 -0400 |
commit | cda846f101fb1396b6924f1d9b68ac3d42de5403 (patch) | |
tree | 1fa8716c308b8e10156a1caf51d8ff6c98eceea9 /arch/x86 | |
parent | bf8b88e97716feb750c3d34492f00d9c085e1183 (diff) |
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: 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>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/include/asm/processor.h | 7 | ||||
-rw-r--r-- | arch/x86/include/asm/realmode.h | 8 | ||||
-rw-r--r-- | arch/x86/kernel/realmode.c | 8 | ||||
-rw-r--r-- | arch/x86/kernel/setup.c | 2 | ||||
-rw-r--r-- | arch/x86/realmode/rm/header.S | 1 | ||||
-rw-r--r-- | arch/x86/realmode/rm/trampoline_64.S | 32 | ||||
-rw-r--r-- | arch/x86/realmode/rm/trampoline_common.S | 19 |
7 files changed, 49 insertions, 28 deletions
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 4fa7dcceb6c0..404583ccf0cf 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h | |||
@@ -544,13 +544,16 @@ static inline void load_sp0(struct tss_struct *tss, | |||
544 | * enable), so that any CPU's that boot up | 544 | * enable), so that any CPU's that boot up |
545 | * after us can get the correct flags. | 545 | * after us can get the correct flags. |
546 | */ | 546 | */ |
547 | extern unsigned long mmu_cr4_features; | 547 | extern unsigned long mmu_cr4_features; |
548 | extern u32 *trampoline_cr4_features; | ||
548 | 549 | ||
549 | static inline void set_in_cr4(unsigned long mask) | 550 | static inline void set_in_cr4(unsigned long mask) |
550 | { | 551 | { |
551 | unsigned long cr4; | 552 | unsigned long cr4; |
552 | 553 | ||
553 | mmu_cr4_features |= mask; | 554 | mmu_cr4_features |= mask; |
555 | if (trampoline_cr4_features) | ||
556 | *trampoline_cr4_features = mmu_cr4_features; | ||
554 | cr4 = read_cr4(); | 557 | cr4 = read_cr4(); |
555 | cr4 |= mask; | 558 | cr4 |= mask; |
556 | write_cr4(cr4); | 559 | write_cr4(cr4); |
@@ -561,6 +564,8 @@ static inline void clear_in_cr4(unsigned long mask) | |||
561 | unsigned long cr4; | 564 | unsigned long cr4; |
562 | 565 | ||
563 | mmu_cr4_features &= ~mask; | 566 | mmu_cr4_features &= ~mask; |
567 | if (trampoline_cr4_features) | ||
568 | *trampoline_cr4_features = mmu_cr4_features; | ||
564 | cr4 = read_cr4(); | 569 | cr4 = read_cr4(); |
565 | cr4 &= ~mask; | 570 | cr4 &= ~mask; |
566 | write_cr4(cr4); | 571 | write_cr4(cr4); |
diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h index 1421eed1c8e8..937dc6071d76 100644 --- a/arch/x86/include/asm/realmode.h +++ b/arch/x86/include/asm/realmode.h | |||
@@ -24,18 +24,22 @@ struct real_mode_header { | |||
24 | #ifdef CONFIG_X86_32 | 24 | #ifdef CONFIG_X86_32 |
25 | u32 machine_real_restart_asm; | 25 | u32 machine_real_restart_asm; |
26 | #endif | 26 | #endif |
27 | } __attribute__((__packed__)); | 27 | }; |
28 | 28 | ||
29 | /* This must match data at trampoline_32/64.S */ | 29 | /* This must match data at trampoline_32/64.S */ |
30 | struct trampoline_header { | 30 | struct trampoline_header { |
31 | #ifdef CONFIG_X86_32 | 31 | #ifdef CONFIG_X86_32 |
32 | u32 start; | 32 | u32 start; |
33 | u16 gdt_pad; | ||
33 | u16 gdt_limit; | 34 | u16 gdt_limit; |
34 | u32 gdt_base; | 35 | u32 gdt_base; |
35 | #else | 36 | #else |
36 | u64 start; | 37 | u64 start; |
38 | u32 cr4; | ||
39 | u32 efer_low; | ||
40 | u32 efer_high; | ||
37 | #endif | 41 | #endif |
38 | } __attribute__((__packed__)); | 42 | }; |
39 | 43 | ||
40 | extern struct real_mode_header *real_mode_header; | 44 | extern struct real_mode_header *real_mode_header; |
41 | extern unsigned char real_mode_blob_end[]; | 45 | extern unsigned char real_mode_blob_end[]; |
diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c index 712fba8fd774..66ac276cf361 100644 --- a/arch/x86/kernel/realmode.c +++ b/arch/x86/kernel/realmode.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <asm/realmode.h> | 6 | #include <asm/realmode.h> |
7 | 7 | ||
8 | struct real_mode_header *real_mode_header; | 8 | struct real_mode_header *real_mode_header; |
9 | u32 *trampoline_cr4_features; | ||
9 | 10 | ||
10 | void __init setup_real_mode(void) | 11 | void __init setup_real_mode(void) |
11 | { | 12 | { |
@@ -64,7 +65,14 @@ void __init setup_real_mode(void) | |||
64 | trampoline_header->gdt_limit = __BOOT_DS + 7; | 65 | trampoline_header->gdt_limit = __BOOT_DS + 7; |
65 | trampoline_header->gdt_base = __pa(boot_gdt); | 66 | trampoline_header->gdt_base = __pa(boot_gdt); |
66 | #else | 67 | #else |
68 | if (rdmsr_safe(MSR_EFER, &trampoline_header->efer_low, | ||
69 | &trampoline_header->efer_high)) | ||
70 | BUG(); | ||
71 | |||
67 | trampoline_header->start = (u64) secondary_startup_64; | 72 | trampoline_header->start = (u64) secondary_startup_64; |
73 | trampoline_cr4_features = &trampoline_header->cr4; | ||
74 | *trampoline_cr4_features = read_cr4(); | ||
75 | |||
68 | trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd); | 76 | trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd); |
69 | trampoline_pgd[0] = __pa(level3_ident_pgt) + _KERNPG_TABLE; | 77 | trampoline_pgd[0] = __pa(level3_ident_pgt) + _KERNPG_TABLE; |
70 | trampoline_pgd[511] = __pa(level3_kernel_pgt) + _KERNPG_TABLE; | 78 | trampoline_pgd[511] = __pa(level3_kernel_pgt) + _KERNPG_TABLE; |
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 7a14fece9cfc..efcf305210a4 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c | |||
@@ -975,6 +975,8 @@ void __init setup_arch(char **cmdline_p) | |||
975 | if (boot_cpu_data.cpuid_level >= 0) { | 975 | if (boot_cpu_data.cpuid_level >= 0) { |
976 | /* A CPU has %cr4 if and only if it has CPUID */ | 976 | /* A CPU has %cr4 if and only if it has CPUID */ |
977 | mmu_cr4_features = read_cr4(); | 977 | mmu_cr4_features = read_cr4(); |
978 | if (trampoline_cr4_features) | ||
979 | *trampoline_cr4_features = mmu_cr4_features; | ||
978 | } | 980 | } |
979 | 981 | ||
980 | #ifdef CONFIG_X86_32 | 982 | #ifdef CONFIG_X86_32 |
diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S index b4c32632bf16..4612d5382791 100644 --- a/arch/x86/realmode/rm/header.S +++ b/arch/x86/realmode/rm/header.S | |||
@@ -9,6 +9,7 @@ | |||
9 | 9 | ||
10 | .section ".header", "a" | 10 | .section ".header", "a" |
11 | 11 | ||
12 | .balign 16 | ||
12 | GLOBAL(real_mode_header) | 13 | GLOBAL(real_mode_header) |
13 | .long pa_text_start | 14 | .long pa_text_start |
14 | .long pa_ro_end | 15 | .long pa_ro_end |
diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S index 3f7293239365..66e26f088288 100644 --- a/arch/x86/realmode/rm/trampoline_64.S +++ b/arch/x86/realmode/rm/trampoline_64.S | |||
@@ -34,9 +34,9 @@ | |||
34 | #include "realmode.h" | 34 | #include "realmode.h" |
35 | 35 | ||
36 | .text | 36 | .text |
37 | .balign PAGE_SIZE | ||
38 | .code16 | 37 | .code16 |
39 | 38 | ||
39 | .balign PAGE_SIZE | ||
40 | ENTRY(trampoline_start) | 40 | ENTRY(trampoline_start) |
41 | cli # We should be safe anyway | 41 | cli # We should be safe anyway |
42 | wbinvd | 42 | wbinvd |
@@ -65,8 +65,8 @@ ENTRY(trampoline_start) | |||
65 | * to 32 bit. | 65 | * to 32 bit. |
66 | */ | 66 | */ |
67 | 67 | ||
68 | lidtl tidt # load idt with 0, 0 | 68 | lidtl tr_idt # load idt with 0, 0 |
69 | lgdtl tgdt # load gdt with whatever is appropriate | 69 | lgdtl tr_gdt # load gdt with whatever is appropriate |
70 | 70 | ||
71 | movw $__KERNEL_DS, %dx # Data segment descriptor | 71 | movw $__KERNEL_DS, %dx # Data segment descriptor |
72 | 72 | ||
@@ -93,16 +93,17 @@ ENTRY(startup_32) | |||
93 | movl %edx, %fs | 93 | movl %edx, %fs |
94 | movl %edx, %gs | 94 | movl %edx, %gs |
95 | 95 | ||
96 | movl $X86_CR4_PAE, %eax | 96 | movl pa_tr_cr4, %eax |
97 | movl %eax, %cr4 # Enable PAE mode | 97 | movl %eax, %cr4 # Enable PAE mode |
98 | 98 | ||
99 | # Setup trampoline 4 level pagetables | 99 | # Setup trampoline 4 level pagetables |
100 | movl $pa_trampoline_pgd, %eax | 100 | movl $pa_trampoline_pgd, %eax |
101 | movl %eax, %cr3 | 101 | movl %eax, %cr3 |
102 | 102 | ||
103 | # Set up EFER | ||
104 | movl pa_tr_efer, %eax | ||
105 | movl pa_tr_efer + 4, %edx | ||
103 | movl $MSR_EFER, %ecx | 106 | movl $MSR_EFER, %ecx |
104 | movl $((1 << _EFER_LME) | (1 << _EFER_NX)), %eax # Enable Long Mode | ||
105 | xorl %edx, %edx | ||
106 | wrmsr | 107 | wrmsr |
107 | 108 | ||
108 | # Enable paging and in turn activate Long Mode | 109 | # Enable paging and in turn activate Long Mode |
@@ -124,23 +125,4 @@ ENTRY(startup_64) | |||
124 | # Now jump into the kernel using virtual addresses | 125 | # Now jump into the kernel using virtual addresses |
125 | jmpq *tr_start(%rip) | 126 | jmpq *tr_start(%rip) |
126 | 127 | ||
127 | .section ".rodata","a" | ||
128 | .balign 16 | ||
129 | tidt: | ||
130 | .word 0 # idt limit = 0 | ||
131 | .word 0, 0 # idt base = 0L | ||
132 | |||
133 | # Duplicate the global descriptor table | ||
134 | # so the kernel can live anywhere | ||
135 | .balign 16 | ||
136 | .globl tgdt | ||
137 | tgdt: | ||
138 | .short tgdt_end - tgdt - 1 # gdt limit | ||
139 | .long pa_tgdt | ||
140 | .short 0 | ||
141 | .quad 0x00cf9b000000ffff # __KERNEL32_CS | ||
142 | .quad 0x00af9b000000ffff # __KERNEL_CS | ||
143 | .quad 0x00cf93000000ffff # __KERNEL_DS | ||
144 | tgdt_end: | ||
145 | |||
146 | #include "trampoline_common.S" | 128 | #include "trampoline_common.S" |
diff --git a/arch/x86/realmode/rm/trampoline_common.S b/arch/x86/realmode/rm/trampoline_common.S index c3f951c468c5..cac444b942f8 100644 --- a/arch/x86/realmode/rm/trampoline_common.S +++ b/arch/x86/realmode/rm/trampoline_common.S | |||
@@ -1,5 +1,20 @@ | |||
1 | .section ".rodata","a" | 1 | .section ".rodata","a" |
2 | 2 | ||
3 | #ifdef CONFIG_X86_64 | ||
4 | # Duplicate the global descriptor table | ||
5 | # so the kernel can live anywhere | ||
6 | .balign 16 | ||
7 | .globl tr_gdt | ||
8 | tr_gdt: | ||
9 | .short tr_gdt_end - tr_gdt - 1 # gdt limit | ||
10 | .long pa_tr_gdt | ||
11 | .short 0 | ||
12 | .quad 0x00cf9b000000ffff # __KERNEL32_CS | ||
13 | .quad 0x00af9b000000ffff # __KERNEL_CS | ||
14 | .quad 0x00cf93000000ffff # __KERNEL_DS | ||
15 | tr_gdt_end: | ||
16 | #endif | ||
17 | |||
3 | .balign 4 | 18 | .balign 4 |
4 | tr_idt: .fill 1, 6, 0 | 19 | tr_idt: .fill 1, 6, 0 |
5 | 20 | ||
@@ -8,12 +23,16 @@ tr_idt: .fill 1, 6, 0 | |||
8 | .balign 4 | 23 | .balign 4 |
9 | GLOBAL(trampoline_status) .space 4 | 24 | GLOBAL(trampoline_status) .space 4 |
10 | 25 | ||
26 | .balign 8 | ||
11 | GLOBAL(trampoline_header) | 27 | GLOBAL(trampoline_header) |
12 | #ifdef CONFIG_X86_32 | 28 | #ifdef CONFIG_X86_32 |
13 | tr_start: .space 4 | 29 | tr_start: .space 4 |
30 | tr_gdt_pad: .space 2 | ||
14 | tr_gdt: .space 6 | 31 | tr_gdt: .space 6 |
15 | #else | 32 | #else |
16 | tr_start: .space 8 | 33 | tr_start: .space 8 |
34 | GLOBAL(tr_cr4) .space 4 | ||
35 | GLOBAL(tr_efer) .space 8 | ||
17 | #endif | 36 | #endif |
18 | END(trampoline_header) | 37 | END(trampoline_header) |
19 | 38 | ||