Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-only */
0002 /*
0003  *
0004  *  verify_cpu.S - Code for cpu long mode and SSE verification. This
0005  *  code has been borrowed from boot/setup.S and was introduced by
0006  *  Andi Kleen.
0007  *
0008  *  Copyright (c) 2007  Andi Kleen (ak@suse.de)
0009  *  Copyright (c) 2007  Eric Biederman (ebiederm@xmission.com)
0010  *  Copyright (c) 2007  Vivek Goyal (vgoyal@in.ibm.com)
0011  *  Copyright (c) 2010  Kees Cook (kees.cook@canonical.com)
0012  *
0013  *  This is a common code for verification whether CPU supports
0014  *  long mode and SSE or not. It is not called directly instead this
0015  *  file is included at various places and compiled in that context.
0016  *  This file is expected to run in 32bit code.  Currently:
0017  *
0018  *  arch/x86/boot/compressed/head_64.S: Boot cpu verification
0019  *  arch/x86/kernel/trampoline_64.S: secondary processor verification
0020  *  arch/x86/kernel/head_32.S: processor startup
0021  *
0022  *  verify_cpu, returns the status of longmode and SSE in register %eax.
0023  *      0: Success    1: Failure
0024  *
0025  *  On Intel, the XD_DISABLE flag will be cleared as a side-effect.
0026  *
0027  *  The caller needs to check for the error code and take the action
0028  *  appropriately. Either display a message or halt.
0029  */
0030 
0031 #include <asm/cpufeatures.h>
0032 #include <asm/msr-index.h>
0033 
0034 SYM_FUNC_START_LOCAL(verify_cpu)
0035     pushf               # Save caller passed flags
0036     push    $0          # Kill any dangerous flags
0037     popf
0038 
0039 #ifndef __x86_64__
0040     pushfl              # standard way to check for cpuid
0041     popl    %eax
0042     movl    %eax,%ebx
0043     xorl    $0x200000,%eax
0044     pushl   %eax
0045     popfl
0046     pushfl
0047     popl    %eax
0048     cmpl    %eax,%ebx
0049     jz  .Lverify_cpu_no_longmode    # cpu has no cpuid
0050 #endif
0051 
0052     movl    $0x0,%eax       # See if cpuid 1 is implemented
0053     cpuid
0054     cmpl    $0x1,%eax
0055     jb  .Lverify_cpu_no_longmode    # no cpuid 1
0056 
0057     xor %di,%di
0058     cmpl    $0x68747541,%ebx    # AuthenticAMD
0059     jnz .Lverify_cpu_noamd
0060     cmpl    $0x69746e65,%edx
0061     jnz .Lverify_cpu_noamd
0062     cmpl    $0x444d4163,%ecx
0063     jnz .Lverify_cpu_noamd
0064     mov $1,%di          # cpu is from AMD
0065     jmp .Lverify_cpu_check
0066 
0067 .Lverify_cpu_noamd:
0068     cmpl    $0x756e6547,%ebx        # GenuineIntel?
0069     jnz .Lverify_cpu_check
0070     cmpl    $0x49656e69,%edx
0071     jnz .Lverify_cpu_check
0072     cmpl    $0x6c65746e,%ecx
0073     jnz .Lverify_cpu_check
0074 
0075     # only call IA32_MISC_ENABLE when:
0076     # family > 6 || (family == 6 && model >= 0xd)
0077     movl    $0x1, %eax      # check CPU family and model
0078     cpuid
0079     movl    %eax, %ecx
0080 
0081     andl    $0x0ff00f00, %eax   # mask family and extended family
0082     shrl    $8, %eax
0083     cmpl    $6, %eax
0084     ja  .Lverify_cpu_clear_xd   # family > 6, ok
0085     jb  .Lverify_cpu_check  # family < 6, skip
0086 
0087     andl    $0x000f00f0, %ecx   # mask model and extended model
0088     shrl    $4, %ecx
0089     cmpl    $0xd, %ecx
0090     jb  .Lverify_cpu_check  # family == 6, model < 0xd, skip
0091 
0092 .Lverify_cpu_clear_xd:
0093     movl    $MSR_IA32_MISC_ENABLE, %ecx
0094     rdmsr
0095     btrl    $2, %edx        # clear MSR_IA32_MISC_ENABLE_XD_DISABLE
0096     jnc .Lverify_cpu_check  # only write MSR if bit was changed
0097     wrmsr
0098 
0099 .Lverify_cpu_check:
0100     movl    $0x1,%eax       # Does the cpu have what it takes
0101     cpuid
0102     andl    $REQUIRED_MASK0,%edx
0103     xorl    $REQUIRED_MASK0,%edx
0104     jnz .Lverify_cpu_no_longmode
0105 
0106     movl    $0x80000000,%eax    # See if extended cpuid is implemented
0107     cpuid
0108     cmpl    $0x80000001,%eax
0109     jb      .Lverify_cpu_no_longmode    # no extended cpuid
0110 
0111     movl    $0x80000001,%eax    # Does the cpu have what it takes
0112     cpuid
0113     andl    $REQUIRED_MASK1,%edx
0114     xorl    $REQUIRED_MASK1,%edx
0115     jnz     .Lverify_cpu_no_longmode
0116 
0117 .Lverify_cpu_sse_test:
0118     movl    $1,%eax
0119     cpuid
0120     andl    $SSE_MASK,%edx
0121     cmpl    $SSE_MASK,%edx
0122     je  .Lverify_cpu_sse_ok
0123     test    %di,%di
0124     jz  .Lverify_cpu_no_longmode    # only try to force SSE on AMD
0125     movl    $MSR_K7_HWCR,%ecx
0126     rdmsr
0127     btr $15,%eax        # enable SSE
0128     wrmsr
0129     xor %di,%di         # don't loop
0130     jmp .Lverify_cpu_sse_test   # try again
0131 
0132 .Lverify_cpu_no_longmode:
0133     popf                # Restore caller passed flags
0134     movl $1,%eax
0135     RET
0136 .Lverify_cpu_sse_ok:
0137     popf                # Restore caller passed flags
0138     xorl %eax, %eax
0139     RET
0140 SYM_FUNC_END(verify_cpu)