Merge commit 'v2.6.39-rc6' into x86/cleanups
[pandora-kernel.git] / arch / x86 / kernel / verify_cpu.S
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  *      Copyright (c) 2010  Kees Cook (kees.cook@canonical.com)
11  *
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.
18  *      This file is expected to run in 32bit code.  Currently:
19  *
20  *      arch/x86/boot/compressed/head_64.S: Boot cpu verification
21  *      arch/x86/kernel/trampoline_64.S: secondary processor verification
22  *      arch/x86/kernel/head_32.S: processor startup
23  *
24  *      verify_cpu, returns the status of longmode and SSE in register %eax.
25  *              0: Success    1: Failure
26  *
27  *      On Intel, the XD_DISABLE flag will be cleared as a side-effect.
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
33 #include <asm/cpufeature.h>
34 #include <asm/msr-index.h>
35
36 verify_cpu:
37         pushfl                          # Save caller passed flags
38         pushl   $0                      # Kill any dangerous flags
39         popfl
40
41         pushfl                          # standard way to check for cpuid
42         popl    %eax
43         movl    %eax,%ebx
44         xorl    $0x200000,%eax
45         pushl   %eax
46         popfl
47         pushfl
48         popl    %eax
49         cmpl    %eax,%ebx
50         jz      verify_cpu_no_longmode  # cpu has no cpuid
51
52         movl    $0x0,%eax               # See if cpuid 1 is implemented
53         cpuid
54         cmpl    $0x1,%eax
55         jb      verify_cpu_no_longmode  # no cpuid 1
56
57         xor     %di,%di
58         cmpl    $0x68747541,%ebx        # AuthenticAMD
59         jnz     verify_cpu_noamd
60         cmpl    $0x69746e65,%edx
61         jnz     verify_cpu_noamd
62         cmpl    $0x444d4163,%ecx
63         jnz     verify_cpu_noamd
64         mov     $1,%di                  # cpu is from AMD
65         jmp     verify_cpu_check
66
67 verify_cpu_noamd:
68         cmpl    $0x756e6547,%ebx        # GenuineIntel?
69         jnz     verify_cpu_check
70         cmpl    $0x49656e69,%edx
71         jnz     verify_cpu_check
72         cmpl    $0x6c65746e,%ecx
73         jnz     verify_cpu_check
74
75         # only call IA32_MISC_ENABLE when:
76         # family > 6 || (family == 6 && model >= 0xd)
77         movl    $0x1, %eax              # check CPU family and model
78         cpuid
79         movl    %eax, %ecx
80
81         andl    $0x0ff00f00, %eax       # mask family and extended family
82         shrl    $8, %eax
83         cmpl    $6, %eax
84         ja      verify_cpu_clear_xd     # family > 6, ok
85         jb      verify_cpu_check        # family < 6, skip
86
87         andl    $0x000f00f0, %ecx       # mask model and extended model
88         shrl    $4, %ecx
89         cmpl    $0xd, %ecx
90         jb      verify_cpu_check        # family == 6, model < 0xd, skip
91
92 verify_cpu_clear_xd:
93         movl    $MSR_IA32_MISC_ENABLE, %ecx
94         rdmsr
95         btrl    $2, %edx                # clear MSR_IA32_MISC_ENABLE_XD_DISABLE
96         jnc     verify_cpu_check        # only write MSR if bit was changed
97         wrmsr
98
99 verify_cpu_check:
100         movl    $0x1,%eax               # Does the cpu have what it takes
101         cpuid
102         andl    $REQUIRED_MASK0,%edx
103         xorl    $REQUIRED_MASK0,%edx
104         jnz     verify_cpu_no_longmode
105
106         movl    $0x80000000,%eax        # See if extended cpuid is implemented
107         cpuid
108         cmpl    $0x80000001,%eax
109         jb      verify_cpu_no_longmode  # no extended cpuid
110
111         movl    $0x80000001,%eax        # Does the cpu have what it takes
112         cpuid
113         andl    $REQUIRED_MASK1,%edx
114         xorl    $REQUIRED_MASK1,%edx
115         jnz     verify_cpu_no_longmode
116
117 verify_cpu_sse_test:
118         movl    $1,%eax
119         cpuid
120         andl    $SSE_MASK,%edx
121         cmpl    $SSE_MASK,%edx
122         je      verify_cpu_sse_ok
123         test    %di,%di
124         jz      verify_cpu_no_longmode  # only try to force SSE on AMD
125         movl    $MSR_K7_HWCR,%ecx
126         rdmsr
127         btr     $15,%eax                # enable SSE
128         wrmsr
129         xor     %di,%di                 # don't loop
130         jmp     verify_cpu_sse_test     # try again
131
132 verify_cpu_no_longmode:
133         popfl                           # Restore caller passed flags
134         movl $1,%eax
135         ret
136 verify_cpu_sse_ok:
137         popfl                           # Restore caller passed flags
138         xorl %eax, %eax
139         ret