aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorJarkko Sakkinen <jarkko.sakkinen@intel.com>2012-05-08 14:22:40 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2012-05-08 14:48:11 -0400
commit8e029fcdd8702719c9179317cae9ef84ebe7027e (patch)
tree12140b7331764ff0e0cd4e0d7bd290453d51110f /arch
parent6feb592dceaed1a6cf26c9747b1180958d5156cd (diff)
x86, realmode: fix 64-bit wakeup sequence
There were number of issues in wakeup sequence: - Wakeup stack was placed in hardcoded address. - NX bit in EFER was not enabled. - Initialization incorrectly set physical address of secondary_startup_64. - Some alignment issues. This patch fixes these issues and in addition: - Unifies coding conventions in .S files. - Sets alignments of code and data right. Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@intel.com> Link: http://lkml.kernel.org/r/1336501366-28617-18-git-send-email-jarkko.sakkinen@intel.com Originally-by: H. Peter Anvin <hpa@linux.intel.com> Cc: Rafael J. Wysocki <rjw@sisk.pl> Cc: Len Brown <len.brown@intel.com> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kernel/realmode.c2
-rw-r--r--arch/x86/realmode/rm/Makefile1
-rw-r--r--arch/x86/realmode/rm/header.S2
-rw-r--r--arch/x86/realmode/rm/reboot_32.S18
-rw-r--r--arch/x86/realmode/rm/stack.S19
-rw-r--r--arch/x86/realmode/rm/trampoline_32.S29
-rw-r--r--arch/x86/realmode/rm/trampoline_64.S67
-rw-r--r--arch/x86/realmode/rm/wakeup/wakeup_asm.S75
-rw-r--r--arch/x86/realmode/rmpiggy.S4
9 files changed, 110 insertions, 107 deletions
diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c
index d85ac20bb4eb..e7bf82a409bf 100644
--- a/arch/x86/kernel/realmode.c
+++ b/arch/x86/kernel/realmode.c
@@ -64,7 +64,7 @@ void __init setup_real_mode(void)
64 *((u32 *)__va(real_mode_header.boot_gdt)) = __pa(boot_gdt); 64 *((u32 *)__va(real_mode_header.boot_gdt)) = __pa(boot_gdt);
65#else 65#else
66 *((u64 *) __va(real_mode_header.startup_64_smp)) = 66 *((u64 *) __va(real_mode_header.startup_64_smp)) =
67 (u64) __pa(secondary_startup_64); 67 (u64)secondary_startup_64;
68 68
69 *((u64 *) __va(real_mode_header.level3_ident_pgt)) = 69 *((u64 *) __va(real_mode_header.level3_ident_pgt)) =
70 __pa(level3_ident_pgt) + _KERNPG_TABLE; 70 __pa(level3_ident_pgt) + _KERNPG_TABLE;
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index 2423142b4da4..c2c27a41ab8f 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -13,6 +13,7 @@ always := realmode.bin
13 13
14realmode-y += header.o 14realmode-y += header.o
15realmode-y += trampoline_$(BITS).o 15realmode-y += trampoline_$(BITS).o
16realmode-y += stack.o
16realmode-$(CONFIG_X86_32) += reboot_32.o 17realmode-$(CONFIG_X86_32) += reboot_32.o
17realmode-$(CONFIG_ACPI_SLEEP) += wakeup/wakeup.o 18realmode-$(CONFIG_ACPI_SLEEP) += wakeup/wakeup.o
18 19
diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
index 730b1316c099..a91ec8f6b15f 100644
--- a/arch/x86/realmode/rm/header.S
+++ b/arch/x86/realmode/rm/header.S
@@ -9,7 +9,7 @@
9 9
10 .section ".header", "a" 10 .section ".header", "a"
11 11
12ENTRY(real_mode_header) 12GLOBAL(real_mode_header)
13 .long pa_text_start 13 .long pa_text_start
14 .long pa_ro_end 14 .long pa_ro_end
15 .long pa_end 15 .long pa_end
diff --git a/arch/x86/realmode/rm/reboot_32.S b/arch/x86/realmode/rm/reboot_32.S
index 50ba994ba921..8d9bfd13a93e 100644
--- a/arch/x86/realmode/rm/reboot_32.S
+++ b/arch/x86/realmode/rm/reboot_32.S
@@ -16,10 +16,9 @@
16 */ 16 */
17 .section ".text32", "ax" 17 .section ".text32", "ax"
18 .code32 18 .code32
19 .globl machine_real_restart_asm
20 19
21 .balign 16 20 .balign 16
22machine_real_restart_asm: 21ENTRY(machine_real_restart_asm)
23 /* Set up the IDT for real mode. */ 22 /* Set up the IDT for real mode. */
24 lidtl pa_machine_real_restart_idt 23 lidtl pa_machine_real_restart_idt
25 24
@@ -67,7 +66,7 @@ machine_real_restart_asm:
67 .text 66 .text
68 .code16 67 .code16
69 68
70 .balign 16 69 .balign 16
71machine_real_restart_asm16: 70machine_real_restart_asm16:
721: 711:
73 xorl %ecx, %ecx 72 xorl %ecx, %ecx
@@ -102,15 +101,15 @@ bios:
102 ljmpw $0xf000, $0xfff0 101 ljmpw $0xf000, $0xfff0
103 102
104 .section ".rodata", "a" 103 .section ".rodata", "a"
105 .globl machine_real_restart_idt, machine_real_restart_gdt
106 104
107 .balign 16 105 .balign 16
108machine_real_restart_idt: 106GLOBAL(machine_real_restart_idt)
109 .word 0xffff /* Length - real mode default value */ 107 .word 0xffff /* Length - real mode default value */
110 .long 0 /* Base - real mode default value */ 108 .long 0 /* Base - real mode default value */
109END(machine_real_restart_idt)
111 110
112 .balign 16 111 .balign 16
113machine_real_restart_gdt: 112GLOBAL(machine_real_restart_gdt)
114 /* Self-pointer */ 113 /* Self-pointer */
115 .word 0xffff /* Length - real mode default value */ 114 .word 0xffff /* Length - real mode default value */
116 .long pa_machine_real_restart_gdt 115 .long pa_machine_real_restart_gdt
@@ -130,3 +129,4 @@ machine_real_restart_gdt:
130 * semantics we don't have to reload the segments once CR0.PE = 0. 129 * semantics we don't have to reload the segments once CR0.PE = 0.
131 */ 130 */
132 .quad GDT_ENTRY(0x0093, 0x100, 0xffff) 131 .quad GDT_ENTRY(0x0093, 0x100, 0xffff)
132END(machine_real_restart_gdt)
diff --git a/arch/x86/realmode/rm/stack.S b/arch/x86/realmode/rm/stack.S
new file mode 100644
index 000000000000..867ae87adfae
--- /dev/null
+++ b/arch/x86/realmode/rm/stack.S
@@ -0,0 +1,19 @@
1/*
2 * Common heap and stack allocations
3 */
4
5#include <linux/linkage.h>
6
7 .data
8GLOBAL(HEAP)
9 .long rm_heap
10GLOBAL(heap_end)
11 .long rm_stack
12
13 .bss
14 .balign 16
15GLOBAL(rm_heap)
16 .space 2048
17GLOBAL(rm_stack)
18 .space 2048
19GLOBAL(rm_stack_end)
diff --git a/arch/x86/realmode/rm/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S
index 279f82ef7a9e..1ecdbb59191b 100644
--- a/arch/x86/realmode/rm/trampoline_32.S
+++ b/arch/x86/realmode/rm/trampoline_32.S
@@ -33,10 +33,9 @@
33 33
34 .text 34 .text
35 .code16 35 .code16
36 .globl trampoline_data
37 36
38 .balign PAGE_SIZE 37 .balign PAGE_SIZE
39trampoline_data: 38ENTRY(trampoline_data)
40 wbinvd # Needed for NUMA-Q should be harmless for others 39 wbinvd # Needed for NUMA-Q should be harmless for others
41 40
42 LJMPW_RM(1f) 41 LJMPW_RM(1f)
@@ -70,20 +69,22 @@ trampoline_data:
70ENTRY(startup_32) # note: also used from wakeup_asm.S 69ENTRY(startup_32) # note: also used from wakeup_asm.S
71 jmp *%eax 70 jmp *%eax
72 71
73 .data 72 .section ".rodata","a"
74 .globl startup_32_smp, boot_gdt, trampoline_status
75 .balign 4
76boot_gdt_descr:
77 .word __BOOT_DS + 7 # gdt limit
78boot_gdt:
79 .long 0 # gdt base
80 73
74 .balign 4
81boot_idt_descr: 75boot_idt_descr:
82 .word 0 # idt limit = 0 76 .word 0 # idt limit = 0
83 .long 0 # idt base = 0L 77 .long 0 # idt base = 0L
84 78
85trampoline_status: 79 .data
86 .long 0
87 80
88startup_32_smp: 81boot_gdt_descr:
89 .long 0 82 .word __BOOT_DS + 7 # gdt limit
83GLOBAL(boot_gdt)
84 .long 0 # gdt base
85
86 .bss
87
88 .balign 4
89GLOBAL(trampoline_status) .space 4
90GLOBAL(startup_32_smp) .space 4
diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S
index 7459c52f0c25..f71ea0800d3d 100644
--- a/arch/x86/realmode/rm/trampoline_64.S
+++ b/arch/x86/realmode/rm/trampoline_64.S
@@ -52,7 +52,7 @@ ENTRY(trampoline_data)
52 # write marker for master knows we're running 52 # write marker for master knows we're running
53 53
54 # Setup stack 54 # Setup stack
55 movw $trampoline_stack_end, %sp 55 movl $rm_stack_end, %esp
56 56
57 call verify_cpu # Verify the cpu supports long mode 57 call verify_cpu # Verify the cpu supports long mode
58 testl %eax, %eax # Check for return code 58 testl %eax, %eax # Check for return code
@@ -68,8 +68,11 @@ ENTRY(trampoline_data)
68 lidtl tidt # load idt with 0, 0 68 lidtl tidt # load idt with 0, 0
69 lgdtl tgdt # load gdt with whatever is appropriate 69 lgdtl tgdt # load gdt with whatever is appropriate
70 70
71 mov $X86_CR0_PE, %ax # protected mode (PE) bit 71 movw $__KERNEL_DS, %dx # Data segment descriptor
72 lmsw %ax # into protected mode 72
73 # Enable protected mode
74 movl $X86_CR0_PE, %eax # protected mode (PE) bit
75 movl %eax, %cr0 # into protected mode
73 76
74 # flush prefetch and jump to startup_32 77 # flush prefetch and jump to startup_32
75 ljmpl $__KERNEL32_CS, $pa_startup_32 78 ljmpl $__KERNEL32_CS, $pa_startup_32
@@ -83,27 +86,27 @@ no_longmode:
83 .code32 86 .code32
84 .balign 4 87 .balign 4
85ENTRY(startup_32) 88ENTRY(startup_32)
86 movl $__KERNEL_DS, %eax # Initialize the %ds segment register 89 movl %edx, %ss
87 movl %eax, %ds 90 addl $pa_real_mode_base, %esp
91 movl %edx, %ds
92 movl %edx, %es
93 movl %edx, %fs
94 movl %edx, %gs
88 95
89 movl $X86_CR4_PAE, %eax 96 movl $X86_CR4_PAE, %eax
90 movl %eax, %cr4 # Enable PAE mode 97 movl %eax, %cr4 # Enable PAE mode
91 98
92 movl pa_startup_64_smp, %esi 99 # Setup trampoline 4 level pagetables
93 movl pa_startup_64_smp_high, %edi 100 movl $pa_level3_ident_pgt, %eax
94
95 # Setup trampoline 4 level pagetables
96 leal pa_trampoline_level4_pgt, %eax
97 movl %eax, %cr3 101 movl %eax, %cr3
98 102
99 movl $MSR_EFER, %ecx 103 movl $MSR_EFER, %ecx
100 movl $(1 << _EFER_LME), %eax # Enable Long Mode 104 movl $((1 << _EFER_LME) | (1 << _EFER_NX)), %eax # Enable Long Mode
101 xorl %edx, %edx 105 xorl %edx, %edx
102 wrmsr 106 wrmsr
103 107
104 # Enable paging and in turn activate Long Mode 108 # Enable paging and in turn activate Long Mode
105 # Enable protected mode 109 movl $(X86_CR0_PG | X86_CR0_WP | X86_CR0_PE), %eax
106 movl $(X86_CR0_PG | X86_CR0_PE), %eax
107 movl %eax, %cr0 110 movl %eax, %cr0
108 111
109 /* 112 /*
@@ -119,10 +122,7 @@ ENTRY(startup_32)
119 .balign 4 122 .balign 4
120ENTRY(startup_64) 123ENTRY(startup_64)
121 # Now jump into the kernel using virtual addresses 124 # Now jump into the kernel using virtual addresses
122 movl %edi, %eax 125 jmpq *startup_64_smp(%rip)
123 shlq $32, %rax
124 addl %esi, %eax
125 jmp *%rax
126 126
127 .section ".rodata","a" 127 .section ".rodata","a"
128 .balign 16 128 .balign 16
@@ -132,10 +132,10 @@ tidt:
132 132
133 # Duplicate the global descriptor table 133 # Duplicate the global descriptor table
134 # so the kernel can live anywhere 134 # so the kernel can live anywhere
135 .balign 4 135 .balign 16
136 .globl tgdt 136 .globl tgdt
137tgdt: 137tgdt:
138 .short tgdt_end - tgdt # gdt limit 138 .short tgdt_end - tgdt - 1 # gdt limit
139 .long pa_tgdt 139 .long pa_tgdt
140 .short 0 140 .short 0
141 .quad 0x00cf9b000000ffff # __KERNEL32_CS 141 .quad 0x00cf9b000000ffff # __KERNEL32_CS
@@ -143,23 +143,12 @@ tgdt:
143 .quad 0x00cf93000000ffff # __KERNEL_DS 143 .quad 0x00cf93000000ffff # __KERNEL_DS
144tgdt_end: 144tgdt_end:
145 145
146 .data 146 .bss
147 .balign 4 147
148GLOBAL(trampoline_status) 148 .balign PAGE_SIZE
149 .long 0 149GLOBAL(level3_ident_pgt) .space 511*8
150 150GLOBAL(level3_kernel_pgt) .space 8
151trampoline_stack: 151
152 .org 0x1000 152 .balign 8
153trampoline_stack_end: 153GLOBAL(startup_64_smp) .space 8
154 154GLOBAL(trampoline_status) .space 4
155 .globl level3_ident_pgt
156 .globl level3_kernel_pgt
157GLOBAL(trampoline_level4_pgt)
158 level3_ident_pgt: .quad 0
159 .fill 510,8,0
160 level3_kernel_pgt: .quad 0
161
162 .globl startup_64_smp
163 .globl startup_64_smp_high
164startup_64_smp: .long 0
165startup_64_smp_high: .long 0
diff --git a/arch/x86/realmode/rm/wakeup/wakeup_asm.S b/arch/x86/realmode/rm/wakeup/wakeup_asm.S
index 8064e1c3591b..f81c1cd99eaf 100644
--- a/arch/x86/realmode/rm/wakeup/wakeup_asm.S
+++ b/arch/x86/realmode/rm/wakeup/wakeup_asm.S
@@ -1,6 +1,7 @@
1/* 1/*
2 * ACPI wakeup real mode startup stub 2 * ACPI wakeup real mode startup stub
3 */ 3 */
4#include <linux/linkage.h>
4#include <asm/segment.h> 5#include <asm/segment.h>
5#include <asm/msr-index.h> 6#include <asm/msr-index.h>
6#include <asm/page_types.h> 7#include <asm/page_types.h>
@@ -9,31 +10,33 @@
9#include "../realmode.h" 10#include "../realmode.h"
10#include "wakeup.h" 11#include "wakeup.h"
11 12
12 .code16 13 .code16
13 14
14/* This should match the structure in wakeup.h */ 15/* This should match the structure in wakeup.h */
15 .section ".data", "aw" 16 .section ".data", "aw"
16 .globl wakeup_header 17
17wakeup_header: 18 .balign 16
18video_mode: .short 0 /* Video mode number */ 19GLOBAL(wakeup_header)
19pmode_entry: .long 0 20 video_mode: .short 0 /* Video mode number */
20pmode_cs: .short __KERNEL_CS 21 pmode_entry: .long 0
21pmode_cr0: .long 0 /* Saved %cr0 */ 22 pmode_cs: .short __KERNEL_CS
22pmode_cr3: .long 0 /* Saved %cr3 */ 23 pmode_cr0: .long 0 /* Saved %cr0 */
23pmode_cr4: .long 0 /* Saved %cr4 */ 24 pmode_cr3: .long 0 /* Saved %cr3 */
24pmode_efer: .quad 0 /* Saved EFER */ 25 pmode_cr4: .long 0 /* Saved %cr4 */
25pmode_gdt: .quad 0 26 pmode_efer: .quad 0 /* Saved EFER */
26pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */ 27 pmode_gdt: .quad 0
27pmode_behavior: .long 0 /* Wakeup behavior flags */ 28 pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */
28realmode_flags: .long 0 29 pmode_behavior: .long 0 /* Wakeup behavior flags */
29real_magic: .long 0 30 realmode_flags: .long 0
30signature: .long WAKEUP_HEADER_SIGNATURE 31 real_magic: .long 0
31 .size wakeup_header, .-wakeup_header 32 signature: .long WAKEUP_HEADER_SIGNATURE
33END(wakeup_header)
32 34
33 .text 35 .text
34 .code16 36 .code16
35 .globl wakeup_start 37
36wakeup_start: 38 .balign 16
39ENTRY(wakeup_start)
37 cli 40 cli
38 cld 41 cld
39 42
@@ -62,12 +65,14 @@ wakeup_start:
623: 653:
63 /* Set up segments */ 66 /* Set up segments */
64 movw %cs, %ax 67 movw %cs, %ax
68 movw %ax, %ss
69 movl $rm_stack_end, %esp
65 movw %ax, %ds 70 movw %ax, %ds
66 movw %ax, %es 71 movw %ax, %es
67 movw %ax, %ss 72 movw %ax, %fs
68 lidtl wakeup_idt 73 movw %ax, %gs
69 74
70 movl $wakeup_stack_end, %esp 75 lidtl wakeup_idt
71 76
72 /* Clear the EFLAGS */ 77 /* Clear the EFLAGS */
73 pushl $0 78 pushl $0
@@ -145,9 +150,8 @@ bogus_real_magic:
145 * be the case for other laptops or integrated video devices. 150 * be the case for other laptops or integrated video devices.
146 */ 151 */
147 152
148 .globl wakeup_gdt
149 .balign 16 153 .balign 16
150wakeup_gdt: 154GLOBAL(wakeup_gdt)
151 .word 3*8-1 /* Self-descriptor */ 155 .word 3*8-1 /* Self-descriptor */
152 .long pa_wakeup_gdt 156 .long pa_wakeup_gdt
153 .word 0 157 .word 0
@@ -159,29 +163,18 @@ wakeup_gdt:
159 .word 0xffff /* 16-bit data segment @ real_mode_base */ 163 .word 0xffff /* 16-bit data segment @ real_mode_base */
160 .long 0x93000000 + pa_real_mode_base 164 .long 0x93000000 + pa_real_mode_base
161 .word 0x008f /* big real mode */ 165 .word 0x008f /* big real mode */
162 .size wakeup_gdt, .-wakeup_gdt 166END(wakeup_gdt)
163 167
164 .data 168 .section ".rodata","a"
165 .balign 8 169 .balign 8
166 170
167 /* This is the standard real-mode IDT */ 171 /* This is the standard real-mode IDT */
168wakeup_idt: 172 .balign 16
173GLOBAL(wakeup_idt)
169 .word 0xffff /* limit */ 174 .word 0xffff /* limit */
170 .long 0 /* address */ 175 .long 0 /* address */
171 .word 0 176 .word 0
172 177END(wakeup_idt)
173 .globl HEAP, heap_end
174HEAP:
175 .long wakeup_heap
176heap_end:
177 .long wakeup_stack
178
179 .bss
180wakeup_heap:
181 .space 2048
182wakeup_stack:
183 .space 2048
184wakeup_stack_end:
185 178
186 .section ".signature","a" 179 .section ".signature","a"
187end_signature: 180end_signature:
diff --git a/arch/x86/realmode/rmpiggy.S b/arch/x86/realmode/rmpiggy.S
index 6047d7f604cf..fd72a99d12ae 100644
--- a/arch/x86/realmode/rmpiggy.S
+++ b/arch/x86/realmode/rmpiggy.S
@@ -9,10 +9,10 @@
9 9
10 .balign PAGE_SIZE 10 .balign PAGE_SIZE
11 11
12ENTRY(real_mode_blob) 12GLOBAL(real_mode_blob)
13 .incbin "arch/x86/realmode/rm/realmode.bin" 13 .incbin "arch/x86/realmode/rm/realmode.bin"
14END(real_mode_blob) 14END(real_mode_blob)
15 15
16ENTRY(real_mode_relocs) 16GLOBAL(real_mode_relocs)
17 .incbin "arch/x86/realmode/rm/realmode.relocs" 17 .incbin "arch/x86/realmode/rm/realmode.relocs"
18END(real_mode_relocs) 18END(real_mode_relocs)