aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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