[PATCH] x86-64: Move cpu verification code to common file
[linux-2.6] / arch / x86_64 / 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  *
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
33 verify_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
70 verify_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
88 verify_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
103 verify_cpu_no_longmode:
104         popfl                           # Restore caller passed flags
105         movl $1,%eax
106         ret
107 verify_cpu_sse_ok:
108         popfl                           # Restore caller passed flags
109         xorl %eax, %eax
110         ret