1
/* cpuid.c - test for CPU features */
3
* GRUB -- GRand Unified Bootloader
4
* Copyright (C) 2006, 2007, 2009 Free Software Foundation, Inc.
5
* Based on gcc/gcc/config/i386/driver-i386.c
7
* GRUB is free software: you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation, either version 3 of the License, or
10
* (at your option) any later version.
12
* GRUB is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
22
#include <grub/misc.h>
25
#include <grub/command.h>
26
#include <grub/extcmd.h>
27
#include <grub/i386/cpuid.h>
28
#include <grub/i18n.h>
30
#define cpuid(num,a,b,c,d) \
31
asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1" \
32
: "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
35
static const struct grub_arg_option options[] =
37
{"long-mode", 'l', 0, N_("Check for long mode flag (default)."), 0, 0},
41
#define bit_LM (1 << 29)
43
unsigned char grub_cpuid_has_longmode = 0;
46
grub_cmd_cpuid (grub_extcmd_context_t ctxt __attribute__ ((unused)),
47
int argc __attribute__ ((unused)),
48
char **args __attribute__ ((unused)))
50
return grub_cpuid_has_longmode ? GRUB_ERR_NONE
51
: grub_error (GRUB_ERR_TEST_FAILURE, "false");
54
static grub_extcmd_t cmd;
60
grub_cpuid_has_longmode = 1;
62
unsigned int eax, ebx, ecx, edx;
63
unsigned int max_level;
64
unsigned int ext_level;
66
/* See if we can use cpuid. */
67
asm volatile ("pushfl; pushfl; popl %0; movl %0,%1; xorl %2,%0;"
68
"pushl %0; popfl; pushfl; popl %0; popfl"
69
: "=&r" (eax), "=&r" (ebx)
71
if (((eax ^ ebx) & 0x00200000) == 0)
74
/* Check the highest input value for eax. */
75
cpuid (0, eax, ebx, ecx, edx);
76
/* We only look at the first four characters. */
81
cpuid (0x80000000, eax, ebx, ecx, edx);
83
if (ext_level < 0x80000000)
86
cpuid (0x80000001, eax, ebx, ecx, edx);
87
grub_cpuid_has_longmode = !!(edx & bit_LM);
91
cmd = grub_register_extcmd ("cpuid", grub_cmd_cpuid, 0,
92
"[-l]", N_("Check for CPU features."), options);
97
grub_unregister_extcmd (cmd);