root/arch/x86/kernel/verify_cpu.S

/* [<][>][^][v][top][bottom][index][help] */
   1 /* SPDX-License-Identifier: GPL-2.0-only */
   2 /*
   3  *
   4  *      verify_cpu.S - Code for cpu long mode and SSE verification. This
   5  *      code has been borrowed from boot/setup.S and was introduced by
   6  *      Andi Kleen.
   7  *
   8  *      Copyright (c) 2007  Andi Kleen (ak@suse.de)
   9  *      Copyright (c) 2007  Eric Biederman (ebiederm@xmission.com)
  10  *      Copyright (c) 2007  Vivek Goyal (vgoyal@in.ibm.com)
  11  *      Copyright (c) 2010  Kees Cook (kees.cook@canonical.com)
  12  *
  13  *      This is a common code for verification whether CPU supports
  14  *      long mode and SSE or not. It is not called directly instead this
  15  *      file is included at various places and compiled in that context.
  16  *      This file is expected to run in 32bit code.  Currently:
  17  *
  18  *      arch/x86/boot/compressed/head_64.S: Boot cpu verification
  19  *      arch/x86/kernel/trampoline_64.S: secondary processor verification
  20  *      arch/x86/kernel/head_32.S: processor startup
  21  *
  22  *      verify_cpu, returns the status of longmode and SSE in register %eax.
  23  *              0: Success    1: Failure
  24  *
  25  *      On Intel, the XD_DISABLE flag will be cleared as a side-effect.
  26  *
  27  *      The caller needs to check for the error code and take the action
  28  *      appropriately. Either display a message or halt.
  29  */
  30 
  31 #include <asm/cpufeatures.h>
  32 #include <asm/msr-index.h>
  33 
  34 ENTRY(verify_cpu)
  35         pushf                           # Save caller passed flags
  36         push    $0                      # Kill any dangerous flags
  37         popf
  38 
  39 #ifndef __x86_64__
  40         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      .Lverify_cpu_no_longmode        # cpu has no cpuid
  50 #endif
  51 
  52         movl    $0x0,%eax               # See if cpuid 1 is implemented
  53         cpuid
  54         cmpl    $0x1,%eax
  55         jb      .Lverify_cpu_no_longmode        # no cpuid 1
  56 
  57         xor     %di,%di
  58         cmpl    $0x68747541,%ebx        # AuthenticAMD
  59         jnz     .Lverify_cpu_noamd
  60         cmpl    $0x69746e65,%edx
  61         jnz     .Lverify_cpu_noamd
  62         cmpl    $0x444d4163,%ecx
  63         jnz     .Lverify_cpu_noamd
  64         mov     $1,%di                  # cpu is from AMD
  65         jmp     .Lverify_cpu_check
  66 
  67 .Lverify_cpu_noamd:
  68         cmpl    $0x756e6547,%ebx        # GenuineIntel?
  69         jnz     .Lverify_cpu_check
  70         cmpl    $0x49656e69,%edx
  71         jnz     .Lverify_cpu_check
  72         cmpl    $0x6c65746e,%ecx
  73         jnz     .Lverify_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      .Lverify_cpu_clear_xd   # family > 6, ok
  85         jb      .Lverify_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      .Lverify_cpu_check      # family == 6, model < 0xd, skip
  91 
  92 .Lverify_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     .Lverify_cpu_check      # only write MSR if bit was changed
  97         wrmsr
  98 
  99 .Lverify_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     .Lverify_cpu_no_longmode
 105 
 106         movl    $0x80000000,%eax        # See if extended cpuid is implemented
 107         cpuid
 108         cmpl    $0x80000001,%eax
 109         jb      .Lverify_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     .Lverify_cpu_no_longmode
 116 
 117 .Lverify_cpu_sse_test:
 118         movl    $1,%eax
 119         cpuid
 120         andl    $SSE_MASK,%edx
 121         cmpl    $SSE_MASK,%edx
 122         je      .Lverify_cpu_sse_ok
 123         test    %di,%di
 124         jz      .Lverify_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     .Lverify_cpu_sse_test   # try again
 131 
 132 .Lverify_cpu_no_longmode:
 133         popf                            # Restore caller passed flags
 134         movl $1,%eax
 135         ret
 136 .Lverify_cpu_sse_ok:
 137         popf                            # Restore caller passed flags
 138         xorl %eax, %eax
 139         ret
 140 ENDPROC(verify_cpu)

/* [<][>][^][v][top][bottom][index][help] */