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#include <asm/cpufeature.h> 34 35verify_cpu: 36 pushfl # Save caller passed flags 37 pushl $0 # Kill any dangerous flags 38 popfl 39 40 /* minimum CPUID flags for x86-64 as defined by AMD */ 41#define M(x) (1<<(x)) 42#define M2(a,b) M(a)|M(b) 43#define M4(a,b,c,d) M(a)|M(b)|M(c)|M(d) 44 45#define SSE_MASK \ 46 (M2(X86_FEATURE_XMM,X86_FEATURE_XMM2)) 47#define REQUIRED_MASK1 \ 48 (M4(X86_FEATURE_FPU,X86_FEATURE_PSE,X86_FEATURE_TSC,X86_FEATURE_MSR)|\ 49 M4(X86_FEATURE_PAE,X86_FEATURE_CX8,X86_FEATURE_PGE,X86_FEATURE_CMOV)|\ 50 M(X86_FEATURE_FXSR)) 51#define REQUIRED_MASK2 \ 52 (M(X86_FEATURE_LM - 32)) 53 54 pushfl # standard way to check for cpuid 55 popl %eax 56 movl %eax,%ebx 57 xorl $0x200000,%eax 58 pushl %eax 59 popfl 60 pushfl 61 popl %eax 62 cmpl %eax,%ebx 63 jz verify_cpu_no_longmode # cpu has no cpuid 64 65 movl $0x0,%eax # See if cpuid 1 is implemented 66 cpuid 67 cmpl $0x1,%eax 68 jb verify_cpu_no_longmode # no cpuid 1 69 70 xor %di,%di 71 cmpl $0x68747541,%ebx # AuthenticAMD 72 jnz verify_cpu_noamd 73 cmpl $0x69746e65,%edx 74 jnz verify_cpu_noamd 75 cmpl $0x444d4163,%ecx 76 jnz verify_cpu_noamd 77 mov $1,%di # cpu is from AMD 78 79verify_cpu_noamd: 80 movl $0x1,%eax # Does the cpu have what it takes 81 cpuid 82 andl $REQUIRED_MASK1,%edx 83 xorl $REQUIRED_MASK1,%edx 84 jnz verify_cpu_no_longmode 85 86 movl $0x80000000,%eax # See if extended cpuid is implemented 87 cpuid 88 cmpl $0x80000001,%eax 89 jb verify_cpu_no_longmode # no extended cpuid 90 91 movl $0x80000001,%eax # Does the cpu have what it takes 92 cpuid 93 andl $REQUIRED_MASK2,%edx 94 xorl $REQUIRED_MASK2,%edx 95 jnz verify_cpu_no_longmode 96 97verify_cpu_sse_test: 98 movl $1,%eax 99 cpuid 100 andl $SSE_MASK,%edx 101 cmpl $SSE_MASK,%edx 102 je verify_cpu_sse_ok 103 test %di,%di 104 jz verify_cpu_no_longmode # only try to force SSE on AMD 105 movl $0xc0010015,%ecx # HWCR 106 rdmsr 107 btr $15,%eax # enable SSE 108 wrmsr 109 xor %di,%di # don't loop 110 jmp verify_cpu_sse_test # try again 111 112verify_cpu_no_longmode: 113 popfl # Restore caller passed flags 114 movl $1,%eax 115 ret 116verify_cpu_sse_ok: 117 popfl # Restore caller passed flags 118 xorl %eax, %eax 119 ret 120