blob: ccb4136da0aaff0ea4608da1d783f2de1a312810 [file] [log] [blame]
Vivek Goyala4831e02007-05-02 19:27:08 +02001/*
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)
Kees Cookae847392010-11-10 10:35:52 -080010 * Copyright (c) 2010 Kees Cook (kees.cook@canonical.com)
Vivek Goyala4831e02007-05-02 19:27:08 +020011 *
12 * This source code is licensed under the GNU General Public License,
13 * Version 2. See the file COPYING for more details.
14 *
15 * This is a common code for verification whether CPU supports
16 * long mode and SSE or not. It is not called directly instead this
17 * file is included at various places and compiled in that context.
Kees Cookae847392010-11-10 10:35:52 -080018 * This file is expected to run in 32bit code. Currently:
Vivek Goyala4831e02007-05-02 19:27:08 +020019 *
Kees Cookae847392010-11-10 10:35:52 -080020 * arch/x86_64/boot/compressed/head_64.S: Boot cpu verification
21 * arch/x86_64/kernel/trampoline_64.S: secondary processor verfication
Vivek Goyala4831e02007-05-02 19:27:08 +020022 *
Kees Cookae847392010-11-10 10:35:52 -080023 * verify_cpu, returns the status of longmode and SSE in register %eax.
Vivek Goyala4831e02007-05-02 19:27:08 +020024 * 0: Success 1: Failure
25 *
Kees Cookae847392010-11-10 10:35:52 -080026 * On Intel, the XD_DISABLE flag will be cleared as a side-effect.
27 *
Vivek Goyala4831e02007-05-02 19:27:08 +020028 * The caller needs to check for the error code and take the action
29 * appropriately. Either display a message or halt.
30 */
31
Andi Kleen72b1b1d2007-05-02 19:27:20 +020032#include <asm/cpufeature.h>
Brian Gerstcfaa71e2010-07-17 09:03:27 -040033#include <asm/msr-index.h>
Vivek Goyala4831e02007-05-02 19:27:08 +020034
Andi Kleen72b1b1d2007-05-02 19:27:20 +020035verify_cpu:
Vivek Goyala4831e02007-05-02 19:27:08 +020036 pushfl # Save caller passed flags
37 pushl $0 # Kill any dangerous flags
38 popfl
39
Vivek Goyala4831e02007-05-02 19:27:08 +020040 pushfl # standard way to check for cpuid
41 popl %eax
42 movl %eax,%ebx
43 xorl $0x200000,%eax
44 pushl %eax
45 popfl
46 pushfl
47 popl %eax
48 cmpl %eax,%ebx
49 jz verify_cpu_no_longmode # cpu has no cpuid
50
51 movl $0x0,%eax # See if cpuid 1 is implemented
52 cpuid
53 cmpl $0x1,%eax
54 jb verify_cpu_no_longmode # no cpuid 1
55
56 xor %di,%di
57 cmpl $0x68747541,%ebx # AuthenticAMD
58 jnz verify_cpu_noamd
59 cmpl $0x69746e65,%edx
60 jnz verify_cpu_noamd
61 cmpl $0x444d4163,%ecx
62 jnz verify_cpu_noamd
63 mov $1,%di # cpu is from AMD
Kees Cookae847392010-11-10 10:35:52 -080064 jmp verify_cpu_check
Vivek Goyala4831e02007-05-02 19:27:08 +020065
66verify_cpu_noamd:
Kees Cookae847392010-11-10 10:35:52 -080067 cmpl $0x756e6547,%ebx # GenuineIntel?
68 jnz verify_cpu_check
69 cmpl $0x49656e69,%edx
70 jnz verify_cpu_check
71 cmpl $0x6c65746e,%ecx
72 jnz verify_cpu_check
73
74 # only call IA32_MISC_ENABLE when:
75 # family > 6 || (family == 6 && model >= 0xd)
76 movl $0x1, %eax # check CPU family and model
77 cpuid
78 movl %eax, %ecx
79
80 andl $0x0ff00f00, %eax # mask family and extended family
81 shrl $8, %eax
82 cmpl $6, %eax
83 ja verify_cpu_clear_xd # family > 6, ok
84 jb verify_cpu_check # family < 6, skip
85
86 andl $0x000f00f0, %ecx # mask model and extended model
87 shrl $4, %ecx
88 cmpl $0xd, %ecx
89 jb verify_cpu_check # family == 6, model < 0xd, skip
90
91verify_cpu_clear_xd:
92 movl $MSR_IA32_MISC_ENABLE, %ecx
93 rdmsr
94 btrl $2, %edx # clear MSR_IA32_MISC_ENABLE_XD_DISABLE
95 jnc verify_cpu_check # only write MSR if bit was changed
96 wrmsr
97
98verify_cpu_check:
Vivek Goyala4831e02007-05-02 19:27:08 +020099 movl $0x1,%eax # Does the cpu have what it takes
100 cpuid
H. Peter Anvinec481532007-07-11 12:18:29 -0700101 andl $REQUIRED_MASK0,%edx
102 xorl $REQUIRED_MASK0,%edx
Vivek Goyala4831e02007-05-02 19:27:08 +0200103 jnz verify_cpu_no_longmode
104
105 movl $0x80000000,%eax # See if extended cpuid is implemented
106 cpuid
107 cmpl $0x80000001,%eax
108 jb verify_cpu_no_longmode # no extended cpuid
109
110 movl $0x80000001,%eax # Does the cpu have what it takes
111 cpuid
H. Peter Anvinec481532007-07-11 12:18:29 -0700112 andl $REQUIRED_MASK1,%edx
113 xorl $REQUIRED_MASK1,%edx
Vivek Goyala4831e02007-05-02 19:27:08 +0200114 jnz verify_cpu_no_longmode
115
116verify_cpu_sse_test:
117 movl $1,%eax
118 cpuid
119 andl $SSE_MASK,%edx
120 cmpl $SSE_MASK,%edx
121 je verify_cpu_sse_ok
122 test %di,%di
123 jz verify_cpu_no_longmode # only try to force SSE on AMD
Brian Gerstcfaa71e2010-07-17 09:03:27 -0400124 movl $MSR_K7_HWCR,%ecx
Vivek Goyala4831e02007-05-02 19:27:08 +0200125 rdmsr
126 btr $15,%eax # enable SSE
127 wrmsr
128 xor %di,%di # don't loop
129 jmp verify_cpu_sse_test # try again
130
131verify_cpu_no_longmode:
132 popfl # Restore caller passed flags
133 movl $1,%eax
134 ret
135verify_cpu_sse_ok:
136 popfl # Restore caller passed flags
137 xorl %eax, %eax
138 ret