aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVivek Goyal <vgoyal@in.ibm.com>2007-05-02 13:27:07 -0400
committerAndi Kleen <andi@basil.nowhere.org>2007-05-02 13:27:07 -0400
commit275f55170ec2b5d777b070cb8ab9e5d58e65a2a8 (patch)
treeb1124f3cac6975a9ef2a5a65849f9c68e71c1eab
parent7db681d7e4038ad205b5face5cf7f7815633e1b5 (diff)
[PATCH] x86-64: wakeup.S misc cleanups
o Various cleanups. One of the main purpose of cleanups is that make wakeup.S as close as possible to trampoline.S. o Following are the changes - Indentations for comments. - Changed the gdt table to compact form and to resemble the one in trampoline.S - Take the jump to 32bit from real mode using ljmpl. Makes code more readable. - After enabling long mode, directly take a long jump for 64bit mode. No need to take an extra jump to "reach_comaptibility_mode" - Stack is not used after real mode. So don't load stack in 32 bit mode. - No need to enable PGE here. - No need to do extra EFER read, anyway we trash the read contents. - No need to enable system call (EFER_SCE). Anyway it will be enabled when original EFER is restored. - No need to set MP, ET, NE, WP, AM bits in cr0. Very soon we will reload the original cr0 while restroing the processor state. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com> Signed-off-by: Andi Kleen <ak@suse.de>
-rw-r--r--arch/x86_64/kernel/acpi/wakeup.S112
1 files changed, 40 insertions, 72 deletions
diff --git a/arch/x86_64/kernel/acpi/wakeup.S b/arch/x86_64/kernel/acpi/wakeup.S
index 17dbeff64eef..bd4c6f1a6f32 100644
--- a/arch/x86_64/kernel/acpi/wakeup.S
+++ b/arch/x86_64/kernel/acpi/wakeup.S
@@ -30,11 +30,12 @@ wakeup_code:
30 cld 30 cld
31 # setup data segment 31 # setup data segment
32 movw %cs, %ax 32 movw %cs, %ax
33 movw %ax, %ds # Make ds:0 point to wakeup_start 33 movw %ax, %ds # Make ds:0 point to wakeup_start
34 movw %ax, %ss 34 movw %ax, %ss
35 mov $(wakeup_stack - wakeup_code), %sp # Private stack is needed for ASUS board 35 # Private stack is needed for ASUS board
36 mov $(wakeup_stack - wakeup_code), %sp
36 37
37 pushl $0 # Kill any dangerous flags 38 pushl $0 # Kill any dangerous flags
38 popfl 39 popfl
39 40
40 movl real_magic - wakeup_code, %eax 41 movl real_magic - wakeup_code, %eax
@@ -45,7 +46,7 @@ wakeup_code:
45 jz 1f 46 jz 1f
46 lcall $0xc000,$3 47 lcall $0xc000,$3
47 movw %cs, %ax 48 movw %cs, %ax
48 movw %ax, %ds # Bios might have played with that 49 movw %ax, %ds # Bios might have played with that
49 movw %ax, %ss 50 movw %ax, %ss
501: 511:
51 52
@@ -75,9 +76,12 @@ wakeup_code:
75 jmp 1f 76 jmp 1f
761: 771:
77 78
78 .byte 0x66, 0xea # prefix + jmpi-opcode 79 ljmpl *(wakeup_32_vector - wakeup_code)
79 .long wakeup_32 - __START_KERNEL_map 80
80 .word __KERNEL_CS 81 .balign 4
82wakeup_32_vector:
83 .long wakeup_32 - __START_KERNEL_map
84 .word __KERNEL32_CS, 0
81 85
82 .code32 86 .code32
83wakeup_32: 87wakeup_32:
@@ -96,65 +100,50 @@ wakeup_32:
96 jnc bogus_cpu 100 jnc bogus_cpu
97 movl %edx,%edi 101 movl %edx,%edi
98 102
99 movw $__KERNEL_DS, %ax 103 movl $__KERNEL_DS, %eax
100 movw %ax, %ds 104 movl %eax, %ds
101 movw %ax, %es
102 movw %ax, %fs
103 movw %ax, %gs
104 105
105 movw $__KERNEL_DS, %ax
106 movw %ax, %ss
107
108 mov $(wakeup_stack - __START_KERNEL_map), %esp
109 movl saved_magic - __START_KERNEL_map, %eax 106 movl saved_magic - __START_KERNEL_map, %eax
110 cmpl $0x9abcdef0, %eax 107 cmpl $0x9abcdef0, %eax
111 jne bogus_32_magic 108 jne bogus_32_magic
112 109
110 movw $0x0e00 + 'i', %ds:(0xb8012)
111 movb $0xa8, %al ; outb %al, $0x80;
112
113 /* 113 /*
114 * Prepare for entering 64bits mode 114 * Prepare for entering 64bits mode
115 */ 115 */
116 116
117 /* Enable PAE mode and PGE */ 117 /* Enable PAE */
118 xorl %eax, %eax 118 xorl %eax, %eax
119 btsl $5, %eax 119 btsl $5, %eax
120 btsl $7, %eax
121 movl %eax, %cr4 120 movl %eax, %cr4
122 121
123 /* Setup early boot stage 4 level pagetables */ 122 /* Setup early boot stage 4 level pagetables */
124 movl $(wakeup_level4_pgt - __START_KERNEL_map), %eax 123 movl $(wakeup_level4_pgt - __START_KERNEL_map), %eax
125 movl %eax, %cr3 124 movl %eax, %cr3
126 125
127 /* Setup EFER (Extended Feature Enable Register) */
128 movl $MSR_EFER, %ecx
129 rdmsr
130 /* Fool rdmsr and reset %eax to avoid dependences */
131 xorl %eax, %eax
132 /* Enable Long Mode */ 126 /* Enable Long Mode */
127 xorl %eax, %eax
133 btsl $_EFER_LME, %eax 128 btsl $_EFER_LME, %eax
134 /* Enable System Call */
135 btsl $_EFER_SCE, %eax
136 129
137 /* No Execute supported? */ 130 /* No Execute supported? */
138 btl $20,%edi 131 btl $20,%edi
139 jnc 1f 132 jnc 1f
140 btsl $_EFER_NX, %eax 133 btsl $_EFER_NX, %eax
1411:
142 134
143 /* Make changes effective */ 135 /* Make changes effective */
1361: movl $MSR_EFER, %ecx
137 xorl %edx, %edx
144 wrmsr 138 wrmsr
145 wbinvd
146 139
147 xorl %eax, %eax 140 xorl %eax, %eax
148 btsl $31, %eax /* Enable paging and in turn activate Long Mode */ 141 btsl $31, %eax /* Enable paging and in turn activate Long Mode */
149 btsl $0, %eax /* Enable protected mode */ 142 btsl $0, %eax /* Enable protected mode */
150 btsl $1, %eax /* Enable MP */
151 btsl $4, %eax /* Enable ET */
152 btsl $5, %eax /* Enable NE */
153 btsl $16, %eax /* Enable WP */
154 btsl $18, %eax /* Enable AM */
155 143
156 /* Make changes effective */ 144 /* Make changes effective */
157 movl %eax, %cr0 145 movl %eax, %cr0
146
158 /* At this point: 147 /* At this point:
159 CR4.PAE must be 1 148 CR4.PAE must be 1
160 CS.L must be 0 149 CS.L must be 0
@@ -162,11 +151,6 @@ wakeup_32:
162 Next instruction must be a branch 151 Next instruction must be a branch
163 This must be on identity-mapped page 152 This must be on identity-mapped page
164 */ 153 */
165 jmp reach_compatibility_mode
166reach_compatibility_mode:
167 movw $0x0e00 + 'i', %ds:(0xb8012)
168 movb $0xa8, %al ; outb %al, $0x80;
169
170 /* 154 /*
171 * At this point we're in long mode but in 32bit compatibility mode 155 * At this point we're in long mode but in 32bit compatibility mode
172 * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn 156 * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
@@ -174,24 +158,19 @@ reach_compatibility_mode:
174 * the new gdt/idt that has __KERNEL_CS with CS.L = 1. 158 * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
175 */ 159 */
176 160
177 movw $0x0e00 + 'n', %ds:(0xb8014)
178 movb $0xa9, %al ; outb %al, $0x80
179
180 /* Load new GDT with the 64bit segment using 32bit descriptor */
181 movl $(pGDT32 - __START_KERNEL_map), %eax
182 lgdt (%eax)
183
184 movl $(wakeup_jumpvector - __START_KERNEL_map), %eax
185 /* Finally jump in 64bit mode */ 161 /* Finally jump in 64bit mode */
186 ljmp *(%eax) 162 ljmp *(wakeup_long64_vector - __START_KERNEL_map)
187 163
188wakeup_jumpvector: 164 .balign 4
189 .long wakeup_long64 - __START_KERNEL_map 165wakeup_long64_vector:
190 .word __KERNEL_CS 166 .long wakeup_long64 - __START_KERNEL_map
167 .word __KERNEL_CS, 0
191 168
192.code64 169.code64
193 170
194 /* Hooray, we are in Long 64-bit mode (but still running in low memory) */ 171 /* Hooray, we are in Long 64-bit mode (but still running in
172 * low memory)
173 */
195wakeup_long64: 174wakeup_long64:
196 /* 175 /*
197 * We must switch to a new descriptor in kernel space for the GDT 176 * We must switch to a new descriptor in kernel space for the GDT
@@ -201,6 +180,9 @@ wakeup_long64:
201 */ 180 */
202 lgdt cpu_gdt_descr - __START_KERNEL_map 181 lgdt cpu_gdt_descr - __START_KERNEL_map
203 182
183 movw $0x0e00 + 'n', %ds:(0xb8014)
184 movb $0xa9, %al ; outb %al, $0x80
185
204 movw $0x0e00 + 'u', %ds:(0xb8016) 186 movw $0x0e00 + 'u', %ds:(0xb8016)
205 187
206 nop 188 nop
@@ -227,33 +209,19 @@ wakeup_long64:
227 209
228 .align 64 210 .align 64
229gdta: 211gdta:
212 /* Its good to keep gdt in sync with one in trampoline.S */
230 .word 0, 0, 0, 0 # dummy 213 .word 0, 0, 0, 0 # dummy
231 214 /* ??? Why I need the accessed bit set in order for this to work? */
232 .word 0, 0, 0, 0 # unused 215 .quad 0x00cf9b000000ffff # __KERNEL32_CS
233 216 .quad 0x00af9b000000ffff # __KERNEL_CS
234 .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) 217 .quad 0x00cf93000000ffff # __KERNEL_DS
235 .word 0 # base address = 0
236 .word 0x9B00 # code read/exec. ??? Why I need 0x9B00 (as opposed to 0x9A00 in order for this to work?)
237 .word 0x00CF # granularity = 4096, 386
238 # (+5th nibble of limit)
239
240 .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
241 .word 0 # base address = 0
242 .word 0x9200 # data read/write
243 .word 0x00CF # granularity = 4096, 386
244 # (+5th nibble of limit)
245# this is 64bit descriptor for code
246 .word 0xFFFF
247 .word 0
248 .word 0x9A00 # code read/exec
249 .word 0x00AF # as above, but it is long mode and with D=0
250 218
251idt_48a: 219idt_48a:
252 .word 0 # idt limit = 0 220 .word 0 # idt limit = 0
253 .word 0, 0 # idt base = 0L 221 .word 0, 0 # idt base = 0L
254 222
255gdt_48a: 223gdt_48a:
256 .word 0x8000 # gdt limit=2048, 224 .word 0x800 # gdt limit=2048,
257 # 256 GDT entries 225 # 256 GDT entries
258 .word 0, 0 # gdt base (filled in later) 226 .word 0, 0 # gdt base (filled in later)
259 227
@@ -263,7 +231,7 @@ video_mode: .quad 0
263video_flags: .quad 0 231video_flags: .quad 0
264 232
265bogus_real_magic: 233bogus_real_magic:
266 movb $0xba,%al ; outb %al,$0x80 234 movb $0xba,%al ; outb %al,$0x80
267 jmp bogus_real_magic 235 jmp bogus_real_magic
268 236
269bogus_32_magic: 237bogus_32_magic: