aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVivek Goyal <vgoyal@in.ibm.com>2007-05-02 13:27:08 -0400
committerAndi Kleen <andi@basil.nowhere.org>2007-05-02 13:27:08 -0400
commita4831e08b7f3ed51623c9eb25e8c945b76b3eda3 (patch)
treecc38c9df02560fba778dfbff5f389e4ac3b720b9
parent8035d3ea78c2a61a9738c7857742370e0aa74d5c (diff)
[PATCH] x86-64: Move cpu verification code to common file
o This patch moves the code to verify long mode and SSE to a common file. This code is now shared by trampoline.S, wakeup.S, boot/setup.S and boot/compressed/head.S o So far we used to do very limited check in trampoline.S, wakeup.S and in 32bit entry point. Now all the entry paths are forced to do the exhaustive check, including SSE because verify_cpu is shared. o I am keeping this patch as last in the x86 relocatable series because previous patches have got quite some amount of testing done and don't want to distrub that. So that if there is problem introduced by this patch, at least it can be easily isolated. 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/boot/compressed/head.S19
-rw-r--r--arch/x86_64/boot/setup.S65
-rw-r--r--arch/x86_64/kernel/acpi/wakeup.S30
-rw-r--r--arch/x86_64/kernel/trampoline.S51
-rw-r--r--arch/x86_64/kernel/verify_cpu.S110
5 files changed, 152 insertions, 123 deletions
diff --git a/arch/x86_64/boot/compressed/head.S b/arch/x86_64/boot/compressed/head.S
index c353a9266ea4..f9d5692a0106 100644
--- a/arch/x86_64/boot/compressed/head.S
+++ b/arch/x86_64/boot/compressed/head.S
@@ -54,6 +54,15 @@ startup_32:
541: popl %ebp 541: popl %ebp
55 subl $1b, %ebp 55 subl $1b, %ebp
56 56
57/* setup a stack and make sure cpu supports long mode. */
58 movl $user_stack_end, %eax
59 addl %ebp, %eax
60 movl %eax, %esp
61
62 call verify_cpu
63 testl %eax, %eax
64 jnz no_longmode
65
57/* Compute the delta between where we were compiled to run at 66/* Compute the delta between where we were compiled to run at
58 * and where the code will actually run at. 67 * and where the code will actually run at.
59 */ 68 */
@@ -159,13 +168,21 @@ startup_32:
159 /* Jump from 32bit compatibility mode into 64bit mode. */ 168 /* Jump from 32bit compatibility mode into 64bit mode. */
160 lret 169 lret
161 170
171no_longmode:
172 /* This isn't an x86-64 CPU so hang */
1731:
174 hlt
175 jmp 1b
176
177#include "../../kernel/verify_cpu.S"
178
162 /* Be careful here startup_64 needs to be at a predictable 179 /* Be careful here startup_64 needs to be at a predictable
163 * address so I can export it in an ELF header. Bootloaders 180 * address so I can export it in an ELF header. Bootloaders
164 * should look at the ELF header to find this address, as 181 * should look at the ELF header to find this address, as
165 * it may change in the future. 182 * it may change in the future.
166 */ 183 */
167 .code64 184 .code64
168 .org 0x100 185 .org 0x200
169ENTRY(startup_64) 186ENTRY(startup_64)
170 /* We come here either from startup_32 or directly from a 187 /* We come here either from startup_32 or directly from a
171 * 64bit bootloader. If we come here from a bootloader we depend on 188 * 64bit bootloader. If we come here from a bootloader we depend on
diff --git a/arch/x86_64/boot/setup.S b/arch/x86_64/boot/setup.S
index deb3573c7aec..816d04faa2be 100644
--- a/arch/x86_64/boot/setup.S
+++ b/arch/x86_64/boot/setup.S
@@ -299,64 +299,10 @@ loader_ok:
299 movw %cs,%ax 299 movw %cs,%ax
300 movw %ax,%ds 300 movw %ax,%ds
301 301
302 /* minimum CPUID flags for x86-64 */ 302 call verify_cpu
303 /* see http://www.x86-64.org/lists/discuss/msg02971.html */ 303 testl %eax,%eax
304#define SSE_MASK ((1<<25)|(1<<26)) 304 jz sse_ok
305#define REQUIRED_MASK1 ((1<<0)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<8)|\ 305
306 (1<<13)|(1<<15)|(1<<24))
307#define REQUIRED_MASK2 (1<<29)
308
309 pushfl /* standard way to check for cpuid */
310 popl %eax
311 movl %eax,%ebx
312 xorl $0x200000,%eax
313 pushl %eax
314 popfl
315 pushfl
316 popl %eax
317 cmpl %eax,%ebx
318 jz no_longmode /* cpu has no cpuid */
319 movl $0x0,%eax
320 cpuid
321 cmpl $0x1,%eax
322 jb no_longmode /* no cpuid 1 */
323 xor %di,%di
324 cmpl $0x68747541,%ebx /* AuthenticAMD */
325 jnz noamd
326 cmpl $0x69746e65,%edx
327 jnz noamd
328 cmpl $0x444d4163,%ecx
329 jnz noamd
330 mov $1,%di /* cpu is from AMD */
331noamd:
332 movl $0x1,%eax
333 cpuid
334 andl $REQUIRED_MASK1,%edx
335 xorl $REQUIRED_MASK1,%edx
336 jnz no_longmode
337 movl $0x80000000,%eax
338 cpuid
339 cmpl $0x80000001,%eax
340 jb no_longmode /* no extended cpuid */
341 movl $0x80000001,%eax
342 cpuid
343 andl $REQUIRED_MASK2,%edx
344 xorl $REQUIRED_MASK2,%edx
345 jnz no_longmode
346sse_test:
347 movl $1,%eax
348 cpuid
349 andl $SSE_MASK,%edx
350 cmpl $SSE_MASK,%edx
351 je sse_ok
352 test %di,%di
353 jz no_longmode /* only try to force SSE on AMD */
354 movl $0xc0010015,%ecx /* HWCR */
355 rdmsr
356 btr $15,%eax /* enable SSE */
357 wrmsr
358 xor %di,%di /* don't loop */
359 jmp sse_test /* try again */
360no_longmode: 306no_longmode:
361 call beep 307 call beep
362 lea long_mode_panic,%si 308 lea long_mode_panic,%si
@@ -366,7 +312,8 @@ no_longmode_loop:
366long_mode_panic: 312long_mode_panic:
367 .string "Your CPU does not support long mode. Use a 32bit distribution." 313 .string "Your CPU does not support long mode. Use a 32bit distribution."
368 .byte 0 314 .byte 0
369 315
316#include "../kernel/verify_cpu.S"
370sse_ok: 317sse_ok:
371 popw %ds 318 popw %ds
372 319
diff --git a/arch/x86_64/kernel/acpi/wakeup.S b/arch/x86_64/kernel/acpi/wakeup.S
index 766cfbcac1db..8550a6ffa275 100644
--- a/arch/x86_64/kernel/acpi/wakeup.S
+++ b/arch/x86_64/kernel/acpi/wakeup.S
@@ -43,6 +43,11 @@ wakeup_code:
43 cmpl $0x12345678, %eax 43 cmpl $0x12345678, %eax
44 jne bogus_real_magic 44 jne bogus_real_magic
45 45
46 call verify_cpu # Verify the cpu supports long
47 # mode
48 testl %eax, %eax
49 jnz no_longmode
50
46 testl $1, video_flags - wakeup_code 51 testl $1, video_flags - wakeup_code
47 jz 1f 52 jz 1f
48 lcall $0xc000,$3 53 lcall $0xc000,$3
@@ -92,18 +97,6 @@ wakeup_32:
92# Running in this code, but at low address; paging is not yet turned on. 97# Running in this code, but at low address; paging is not yet turned on.
93 movb $0xa5, %al ; outb %al, $0x80 98 movb $0xa5, %al ; outb %al, $0x80
94 99
95 /* Check if extended functions are implemented */
96 movl $0x80000000, %eax
97 cpuid
98 cmpl $0x80000000, %eax
99 jbe bogus_cpu
100 wbinvd
101 mov $0x80000001, %eax
102 cpuid
103 btl $29, %edx
104 jnc bogus_cpu
105 movl %edx,%edi
106
107 movl $__KERNEL_DS, %eax 100 movl $__KERNEL_DS, %eax
108 movl %eax, %ds 101 movl %eax, %ds
109 102
@@ -123,6 +116,11 @@ wakeup_32:
123 leal (wakeup_level4_pgt - wakeup_code)(%esi), %eax 116 leal (wakeup_level4_pgt - wakeup_code)(%esi), %eax
124 movl %eax, %cr3 117 movl %eax, %cr3
125 118
119 /* Check if nx is implemented */
120 movl $0x80000001, %eax
121 cpuid
122 movl %edx,%edi
123
126 /* Enable Long Mode */ 124 /* Enable Long Mode */
127 xorl %eax, %eax 125 xorl %eax, %eax
128 btsl $_EFER_LME, %eax 126 btsl $_EFER_LME, %eax
@@ -244,10 +242,12 @@ bogus_64_magic:
244 movb $0xb3,%al ; outb %al,$0x80 242 movb $0xb3,%al ; outb %al,$0x80
245 jmp bogus_64_magic 243 jmp bogus_64_magic
246 244
247bogus_cpu: 245.code16
248 movb $0xbc,%al ; outb %al,$0x80 246no_longmode:
249 jmp bogus_cpu 247 movb $0xbc,%al ; outb %al,$0x80
248 jmp no_longmode
250 249
250#include "../verify_cpu.S"
251 251
252/* This code uses an extended set of video mode numbers. These include: 252/* This code uses an extended set of video mode numbers. These include:
253 * Aliases for standard modes 253 * Aliases for standard modes
diff --git a/arch/x86_64/kernel/trampoline.S b/arch/x86_64/kernel/trampoline.S
index 13eee63c7bb5..e7e2764c461b 100644
--- a/arch/x86_64/kernel/trampoline.S
+++ b/arch/x86_64/kernel/trampoline.S
@@ -54,6 +54,8 @@ r_base = .
54 movw $(trampoline_stack_end - r_base), %sp 54 movw $(trampoline_stack_end - r_base), %sp
55 55
56 call verify_cpu # Verify the cpu supports long mode 56 call verify_cpu # Verify the cpu supports long mode
57 testl %eax, %eax # Check for return code
58 jnz no_longmode
57 59
58 mov %cs, %ax 60 mov %cs, %ax
59 movzx %ax, %esi # Find the 32bit trampoline location 61 movzx %ax, %esi # Find the 32bit trampoline location
@@ -121,57 +123,10 @@ startup_64:
121 jmp *%rax 123 jmp *%rax
122 124
123 .code16 125 .code16
124verify_cpu:
125 pushl $0 # Kill any dangerous flags
126 popfl
127
128 /* minimum CPUID flags for x86-64 */
129 /* see http://www.x86-64.org/lists/discuss/msg02971.html */
130#define REQUIRED_MASK1 ((1<<0)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<8)|\
131 (1<<13)|(1<<15)|(1<<24)|(1<<25)|(1<<26))
132#define REQUIRED_MASK2 (1<<29)
133
134 pushfl # check for cpuid
135 popl %eax
136 movl %eax, %ebx
137 xorl $0x200000,%eax
138 pushl %eax
139 popfl
140 pushfl
141 popl %eax
142 pushl %ebx
143 popfl
144 cmpl %eax, %ebx
145 jz no_longmode
146
147 xorl %eax, %eax # See if cpuid 1 is implemented
148 cpuid
149 cmpl $0x1, %eax
150 jb no_longmode
151
152 movl $0x01, %eax # Does the cpu have what it takes?
153 cpuid
154 andl $REQUIRED_MASK1, %edx
155 xorl $REQUIRED_MASK1, %edx
156 jnz no_longmode
157
158 movl $0x80000000, %eax # See if extended cpuid is implemented
159 cpuid
160 cmpl $0x80000001, %eax
161 jb no_longmode
162
163 movl $0x80000001, %eax # Does the cpu have what it takes?
164 cpuid
165 andl $REQUIRED_MASK2, %edx
166 xorl $REQUIRED_MASK2, %edx
167 jnz no_longmode
168
169 ret # The cpu supports long mode
170
171no_longmode: 126no_longmode:
172 hlt 127 hlt
173 jmp no_longmode 128 jmp no_longmode
174 129#include "verify_cpu.S"
175 130
176 # Careful these need to be in the same 64K segment as the above; 131 # Careful these need to be in the same 64K segment as the above;
177tidt: 132tidt:
diff --git a/arch/x86_64/kernel/verify_cpu.S b/arch/x86_64/kernel/verify_cpu.S
new file mode 100644
index 000000000000..72edabd2ef9a
--- /dev/null
+++ b/arch/x86_64/kernel/verify_cpu.S
@@ -0,0 +1,110 @@
1/*
2 *
3 * verify_cpu.S - Code for cpu long mode and SSE verification. This
4 * code has been borrowed from boot/setup.S and was introduced by
5 * Andi Kleen.
6 *
7 * Copyright (c) 2007 Andi Kleen (ak@suse.de)
8 * Copyright (c) 2007 Eric Biederman (ebiederm@xmission.com)
9 * Copyright (c) 2007 Vivek Goyal (vgoyal@in.ibm.com)
10 *
11 * This source code is licensed under the GNU General Public License,
12 * Version 2. See the file COPYING for more details.
13 *
14 * This is a common code for verification whether CPU supports
15 * long mode and SSE or not. It is not called directly instead this
16 * file is included at various places and compiled in that context.
17 * Following are the current usage.
18 *
19 * This file is included by both 16bit and 32bit code.
20 *
21 * arch/x86_64/boot/setup.S : Boot cpu verification (16bit)
22 * arch/x86_64/boot/compressed/head.S: Boot cpu verification (32bit)
23 * arch/x86_64/kernel/trampoline.S: secondary processor verfication (16bit)
24 * arch/x86_64/kernel/acpi/wakeup.S:Verfication at resume (16bit)
25 *
26 * verify_cpu, returns the status of cpu check in register %eax.
27 * 0: Success 1: Failure
28 *
29 * The caller needs to check for the error code and take the action
30 * appropriately. Either display a message or halt.
31 */
32
33verify_cpu:
34
35 pushfl # Save caller passed flags
36 pushl $0 # Kill any dangerous flags
37 popfl
38
39 /* minimum CPUID flags for x86-64 */
40 /* see http://www.x86-64.org/lists/discuss/msg02971.html */
41#define SSE_MASK ((1<<25)|(1<<26))
42#define REQUIRED_MASK1 ((1<<0)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<8)|\
43 (1<<13)|(1<<15)|(1<<24))
44#define REQUIRED_MASK2 (1<<29)
45 pushfl # standard way to check for cpuid
46 popl %eax
47 movl %eax,%ebx
48 xorl $0x200000,%eax
49 pushl %eax
50 popfl
51 pushfl
52 popl %eax
53 cmpl %eax,%ebx
54 jz verify_cpu_no_longmode # cpu has no cpuid
55
56 movl $0x0,%eax # See if cpuid 1 is implemented
57 cpuid
58 cmpl $0x1,%eax
59 jb verify_cpu_no_longmode # no cpuid 1
60
61 xor %di,%di
62 cmpl $0x68747541,%ebx # AuthenticAMD
63 jnz verify_cpu_noamd
64 cmpl $0x69746e65,%edx
65 jnz verify_cpu_noamd
66 cmpl $0x444d4163,%ecx
67 jnz verify_cpu_noamd
68 mov $1,%di # cpu is from AMD
69
70verify_cpu_noamd:
71 movl $0x1,%eax # Does the cpu have what it takes
72 cpuid
73 andl $REQUIRED_MASK1,%edx
74 xorl $REQUIRED_MASK1,%edx
75 jnz verify_cpu_no_longmode
76
77 movl $0x80000000,%eax # See if extended cpuid is implemented
78 cpuid
79 cmpl $0x80000001,%eax
80 jb verify_cpu_no_longmode # no extended cpuid
81
82 movl $0x80000001,%eax # Does the cpu have what it takes
83 cpuid
84 andl $REQUIRED_MASK2,%edx
85 xorl $REQUIRED_MASK2,%edx
86 jnz verify_cpu_no_longmode
87
88verify_cpu_sse_test:
89 movl $1,%eax
90 cpuid
91 andl $SSE_MASK,%edx
92 cmpl $SSE_MASK,%edx
93 je verify_cpu_sse_ok
94 test %di,%di
95 jz verify_cpu_no_longmode # only try to force SSE on AMD
96 movl $0xc0010015,%ecx # HWCR
97 rdmsr
98 btr $15,%eax # enable SSE
99 wrmsr
100 xor %di,%di # don't loop
101 jmp verify_cpu_sse_test # try again
102
103verify_cpu_no_longmode:
104 popfl # Restore caller passed flags
105 movl $1,%eax
106 ret
107verify_cpu_sse_ok:
108 popfl # Restore caller passed flags
109 xorl %eax, %eax
110 ret