]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[cmdline] Add "cpuid" command
authorMichael Brown <mcb30@ipxe.org>
Wed, 6 Jun 2012 15:08:24 +0000 (16:08 +0100)
committerMichael Brown <mcb30@ipxe.org>
Wed, 6 Jun 2012 23:37:04 +0000 (00:37 +0100)
Allow x86 CPU feature flags (such as support for 64-bit mode) to be
checked using the "cpuid" command.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/arch/i386/core/cpu.c [deleted file]
src/arch/i386/include/bits/cpu.h [deleted file]
src/arch/x86/Makefile
src/arch/x86/core/cpuid.c [new file with mode: 0644]
src/arch/x86/hci/commands/cpuid_cmd.c [new file with mode: 0644]
src/arch/x86/include/bits/errfile.h
src/arch/x86/include/ipxe/cpuid.h [new file with mode: 0644]
src/config/config.c
src/config/defaults/pcbios.h

diff --git a/src/arch/i386/core/cpu.c b/src/arch/i386/core/cpu.c
deleted file mode 100644 (file)
index c24fa4e..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-#include <stdint.h>
-#include <string.h>
-#include <cpu.h>
-
-/** @file
- *
- * CPU identification
- *
- */
-
-/**
- * Test to see if CPU flag is changeable
- *
- * @v flag             Flag to test
- * @ret can_change     Flag is changeable
- */
-static inline int flag_is_changeable ( unsigned int flag ) {
-       uint32_t f1, f2;
-
-       __asm__ ( "pushfl\n\t"
-                 "pushfl\n\t"
-                 "popl %0\n\t"
-                 "movl %0,%1\n\t"
-                 "xorl %2,%0\n\t"
-                 "pushl %0\n\t"
-                 "popfl\n\t"
-                 "pushfl\n\t"
-                 "popl %0\n\t"
-                 "popfl\n\t"
-                 : "=&r" ( f1 ), "=&r" ( f2 )
-                 : "ir" ( flag ) );
-
-       return ( ( ( f1 ^ f2 ) & flag ) != 0 );
-}
-
-/**
- * Get CPU information
- *
- * @v cpu              CPU information structure to fill in
- */
-void get_cpuinfo ( struct cpuinfo_x86 *cpu ) {
-       unsigned int cpuid_level;
-       unsigned int cpuid_extlevel;
-       unsigned int discard_1, discard_2, discard_3;
-
-       memset ( cpu, 0, sizeof ( *cpu ) );
-
-       /* Check for CPUID instruction */
-       if ( ! flag_is_changeable ( X86_EFLAGS_ID ) ) {
-               DBG ( "CPUID not supported\n" );
-               return;
-       }
-
-       /* Get features, if present */
-       cpuid ( 0x00000000, &cpuid_level, &discard_1,
-               &discard_2, &discard_3 );
-       if ( cpuid_level >= 0x00000001 ) {
-               cpuid ( 0x00000001, &discard_1, &discard_2,
-                       &discard_3, &cpu->features );
-       } else {
-               DBG ( "CPUID cannot return capabilities\n" );
-       }
-
-       /* Get 64-bit features, if present */
-       cpuid ( 0x80000000, &cpuid_extlevel, &discard_1,
-               &discard_2, &discard_3 );
-       if ( ( cpuid_extlevel & 0xffff0000 ) == 0x80000000 ) {
-               if ( cpuid_extlevel >= 0x80000001 ) {
-                       cpuid ( 0x80000001, &discard_1, &discard_2,
-                               &discard_3, &cpu->amd_features );
-               }
-       }
-}
diff --git a/src/arch/i386/include/bits/cpu.h b/src/arch/i386/include/bits/cpu.h
deleted file mode 100644 (file)
index 83339dd..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-#ifndef I386_BITS_CPU_H
-#define I386_BITS_CPU_H
-
-/* Intel-defined CPU features, CPUID level 0x00000001, word 0 */
-#define X86_FEATURE_FPU                0 /* Onboard FPU */
-#define X86_FEATURE_VME                1 /* Virtual Mode Extensions */
-#define X86_FEATURE_DE         2 /* Debugging Extensions */
-#define X86_FEATURE_PSE        3 /* Page Size Extensions */
-#define X86_FEATURE_TSC                4 /* Time Stamp Counter */
-#define X86_FEATURE_MSR                5 /* Model-Specific Registers, RDMSR, WRMSR */
-#define X86_FEATURE_PAE                6 /* Physical Address Extensions */
-#define X86_FEATURE_MCE                7 /* Machine Check Architecture */
-#define X86_FEATURE_CX8                8 /* CMPXCHG8 instruction */
-#define X86_FEATURE_APIC       9 /* Onboard APIC */
-#define X86_FEATURE_SEP                11 /* SYSENTER/SYSEXIT */
-#define X86_FEATURE_MTRR       12 /* Memory Type Range Registers */
-#define X86_FEATURE_PGE                13 /* Page Global Enable */
-#define X86_FEATURE_MCA                14 /* Machine Check Architecture */
-#define X86_FEATURE_CMOV       15 /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */
-#define X86_FEATURE_PAT                16 /* Page Attribute Table */
-#define X86_FEATURE_PSE36      17 /* 36-bit PSEs */
-#define X86_FEATURE_PN         18 /* Processor serial number */
-#define X86_FEATURE_CLFLSH     19 /* Supports the CLFLUSH instruction */
-#define X86_FEATURE_DTES       21 /* Debug Trace Store */
-#define X86_FEATURE_ACPI       22 /* ACPI via MSR */
-#define X86_FEATURE_MMX                23 /* Multimedia Extensions */
-#define X86_FEATURE_FXSR       24 /* FXSAVE and FXRSTOR instructions (fast save and restore */
-                                         /* of FPU context), and CR4.OSFXSR available */
-#define X86_FEATURE_XMM                25 /* Streaming SIMD Extensions */
-#define X86_FEATURE_XMM2       26 /* Streaming SIMD Extensions-2 */
-#define X86_FEATURE_SELFSNOOP  27 /* CPU self snoop */
-#define X86_FEATURE_HT         28 /* Hyper-Threading */
-#define X86_FEATURE_ACC                29 /* Automatic clock control */
-#define X86_FEATURE_IA64       30 /* IA-64 processor */
-
-/* AMD-defined CPU features, CPUID level 0x80000001, word 1 */
-/* Don't duplicate feature flags which are redundant with Intel! */
-#define X86_FEATURE_SYSCALL    11 /* SYSCALL/SYSRET */
-#define X86_FEATURE_MMXEXT     22 /* AMD MMX extensions */
-#define X86_FEATURE_LM         29 /* Long Mode (x86-64) */
-#define X86_FEATURE_3DNOWEXT   30 /* AMD 3DNow! extensions */
-#define X86_FEATURE_3DNOW      31 /* 3DNow! */
-
-/** x86 CPU information */
-struct cpuinfo_x86 {
-       /** CPU features */
-       unsigned int features;
-       /** 64-bit CPU features */
-       unsigned int amd_features;
-};
-
-/*
- * EFLAGS bits
- */
-#define X86_EFLAGS_CF  0x00000001 /* Carry Flag */
-#define X86_EFLAGS_PF  0x00000004 /* Parity Flag */
-#define X86_EFLAGS_AF  0x00000010 /* Auxillary carry Flag */
-#define X86_EFLAGS_ZF  0x00000040 /* Zero Flag */
-#define X86_EFLAGS_SF  0x00000080 /* Sign Flag */
-#define X86_EFLAGS_TF  0x00000100 /* Trap Flag */
-#define X86_EFLAGS_IF  0x00000200 /* Interrupt Flag */
-#define X86_EFLAGS_DF  0x00000400 /* Direction Flag */
-#define X86_EFLAGS_OF  0x00000800 /* Overflow Flag */
-#define X86_EFLAGS_IOPL        0x00003000 /* IOPL mask */
-#define X86_EFLAGS_NT  0x00004000 /* Nested Task */
-#define X86_EFLAGS_RF  0x00010000 /* Resume Flag */
-#define X86_EFLAGS_VM  0x00020000 /* Virtual Mode */
-#define X86_EFLAGS_AC  0x00040000 /* Alignment Check */
-#define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */
-#define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
-#define X86_EFLAGS_ID  0x00200000 /* CPUID detection flag */
-
-/*
- * Generic CPUID function
- */
-static inline __attribute__ (( always_inline )) void
-cpuid ( int op, unsigned int *eax, unsigned int *ebx,
-       unsigned int *ecx, unsigned int *edx ) {
-       __asm__ ( "cpuid" :
-                 "=a" ( *eax ), "=b" ( *ebx ), "=c" ( *ecx ), "=d" ( *edx )
-               : "0" ( op ) );
-}
-
-extern void get_cpuinfo ( struct cpuinfo_x86 *cpu );
-
-#endif /* I386_BITS_CPU_H */
index 37e03aafa316bfacfab21194c4610f3fc3a9c14e..cdd397d40093230f55b59b427e4545dcd5387103 100644 (file)
@@ -7,6 +7,7 @@ INCDIRS         += arch/x86/include
 SRCDIRS                += arch/x86/core
 SRCDIRS                += arch/x86/interface/efi
 SRCDIRS                += arch/x86/prefix
+SRCDIRS                += arch/x86/hci/commands
 
 # breaks building some of the linux-related objects
 CFLAGS         += -Ulinux
diff --git a/src/arch/x86/core/cpuid.c b/src/arch/x86/core/cpuid.c
new file mode 100644 (file)
index 0000000..cf9dd6d
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <ipxe/cpuid.h>
+
+/** @file
+ *
+ * x86 CPU feature detection
+ *
+ */
+
+/**
+ * Check whether or not CPUID instruction is supported
+ *
+ * @ret is_supported   CPUID instruction is supported
+ */
+static int cpuid_is_supported ( void ) {
+       unsigned long original;
+       unsigned long inverted;
+
+       __asm__ ( "pushf\n\t"
+                 "pushf\n\t"
+                 "pop %0\n\t"
+                 "mov %0,%1\n\t"
+                 "xor %2,%1\n\t"
+                 "push %1\n\t"
+                 "popf\n\t"
+                 "pushf\n\t"
+                 "pop %1\n\t"
+                 "popf\n\t"
+                 : "=&r" ( original ), "=&r" ( inverted )
+                 : "ir" ( CPUID_FLAG ) );
+       return ( ( original ^ inverted ) & CPUID_FLAG );
+}
+
+/**
+ * Issue CPUID instruction
+ *
+ * @v operation                CPUID operation
+ * @v eax              Output via %eax
+ * @v ebx              Output via %ebx
+ * @v ecx              Output via %ecx
+ * @v edx              Output via %edx
+ */
+static inline __attribute__ (( always_inline )) void
+cpuid ( uint32_t operation, uint32_t *eax, uint32_t *ebx, uint32_t *ecx,
+       uint32_t *edx ) {
+
+       __asm__ ( "cpuid"
+                 : "=a" ( *eax ), "=b" ( *ebx ), "=c" ( *ecx ), "=d" ( *edx )
+                 : "0" ( operation ) );
+}
+
+/**
+ * Get Intel-defined x86 CPU features
+ *
+ * @v features         x86 CPU features to fill in
+ */
+static void x86_intel_features ( struct x86_features *features ) {
+       uint32_t max_level;
+       uint32_t discard_a;
+       uint32_t discard_b;
+       uint32_t discard_c;
+       uint32_t discard_d;
+
+       /* Check that features are available via CPUID */
+       cpuid ( CPUID_VENDOR_ID, &max_level, &discard_b, &discard_c,
+               &discard_d );
+       if ( max_level < CPUID_FEATURES ) {
+               DBGC ( features, "CPUID has no Intel-defined features (max "
+                      "level %08x)\n", max_level );
+               return;
+       }
+
+       /* Get features */
+       cpuid ( CPUID_FEATURES, &discard_a, &discard_b,
+               &features->intel.ecx, &features->intel.edx );
+       DBGC ( features, "CPUID Intel features: %%ecx=%08x, %%edx=%08x\n",
+              features->intel.ecx, features->intel.edx );
+
+}
+
+/**
+ * Get AMD-defined x86 CPU features
+ *
+ * @v features         x86 CPU features to fill in
+ */
+static void x86_amd_features ( struct x86_features *features ) {
+       uint32_t max_level;
+       uint32_t discard_a;
+       uint32_t discard_b;
+       uint32_t discard_c;
+       uint32_t discard_d;
+
+       /* Check that features are available via CPUID */
+       cpuid ( CPUID_AMD_MAX_FN, &max_level, &discard_b, &discard_c,
+               &discard_d );
+       if ( ( max_level & CPUID_AMD_CHECK_MASK ) != CPUID_AMD_CHECK ) {
+               DBGC ( features, "CPUID has no extended functions\n" );
+               return;
+       }
+       if ( max_level < CPUID_AMD_FEATURES ) {
+               DBGC ( features, "CPUID has no AMD-defined features (max "
+                      "level %08x)\n", max_level );
+               return;
+       }
+
+       /* Get features */
+       cpuid ( CPUID_AMD_FEATURES, &discard_a, &discard_b,
+               &features->amd.ecx, &features->amd.edx );
+       DBGC ( features, "CPUID AMD features: %%ecx=%08x, %%edx=%08x\n",
+              features->amd.ecx, features->amd.edx );
+}
+
+/**
+ * Get x86 CPU features
+ *
+ * @v features         x86 CPU features to fill in
+ */
+void x86_features ( struct x86_features *features ) {
+
+       /* Clear all features */
+       memset ( features, 0, sizeof ( *features ) );
+
+       /* Check that CPUID instruction is available */
+       if ( ! cpuid_is_supported() ) {
+               DBGC ( features, "CPUID instruction is not supported\n" );
+               return;
+       }
+
+       /* Get Intel-defined features */
+       x86_intel_features ( features );
+
+       /* Get AMD-defined features */
+       x86_amd_features ( features );
+}
diff --git a/src/arch/x86/hci/commands/cpuid_cmd.c b/src/arch/x86/hci/commands/cpuid_cmd.c
new file mode 100644 (file)
index 0000000..3172727
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdio.h>
+#include <errno.h>
+#include <getopt.h>
+#include <ipxe/cpuid.h>
+#include <ipxe/command.h>
+#include <ipxe/parseopt.h>
+
+/** @file
+ *
+ * x86 CPU feature detection command
+ *
+ */
+
+/** "cpuid" options */
+struct cpuid_options {
+       /** Check AMD-defined features (%eax=0x80000001) */
+       int amd;
+       /** Check features defined via %ecx */
+       int ecx;
+};
+
+/** "cpuid" option list */
+static struct option_descriptor cpuid_opts[] = {
+       OPTION_DESC ( "amd", 'a', no_argument,
+                     struct cpuid_options, amd, parse_flag ),
+       OPTION_DESC ( "ecx", 'c', no_argument,
+                     struct cpuid_options, ecx, parse_flag ),
+};
+
+/** "cpuid" command descriptor */
+static struct command_descriptor cpuid_cmd =
+       COMMAND_DESC ( struct cpuid_options, cpuid_opts, 1, 1,
+                      "[--amd] [--ecx] <bit>" );
+
+/**
+ * The "cpuid" command
+ *
+ * @v argc             Argument count
+ * @v argv             Argument list
+ * @ret rc             Return status code
+ */
+static int cpuid_exec ( int argc, char **argv ) {
+       struct cpuid_options opts;
+       struct x86_features features;
+       struct x86_feature_registers *feature_regs;
+       uint32_t feature_reg;
+       unsigned int bit;
+       int rc;
+
+       /* Parse options */
+       if ( ( rc = parse_options ( argc, argv, &cpuid_cmd, &opts ) ) != 0 )
+               return rc;
+
+       /* Parse bit number */
+       if ( ( rc = parse_integer ( argv[optind], &bit ) ) != 0 )
+               return rc;
+
+       /* Get CPU features */
+       x86_features ( &features );
+
+       /* Extract relevant feature register */
+       feature_regs = ( opts.amd ? &features.amd : &features.intel );
+       feature_reg = ( opts.ecx ? feature_regs->ecx : feature_regs->edx );
+
+       /* Check presence of specified feature */
+       return ( ( feature_reg & ( 1 << bit ) ) ? 0 : -ENOENT );
+}
+
+/** x86 CPU feature detection command */
+struct command cpuid_command __command = {
+       .name = "cpuid",
+       .exec = cpuid_exec,
+};
index ccf00b86b8ab7af4ba579839624a0c9d215ee4a8..f66cbaa1a3ad2a39fdf604e5df9b846091899756 100644 (file)
@@ -38,8 +38,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define ERRFILE_undionly        ( ERRFILE_ARCH | ERRFILE_NET | 0x00030000 )
 #define ERRFILE_undirom                 ( ERRFILE_ARCH | ERRFILE_NET | 0x00040000 )
 
-#define ERRFILE_timer_rdtsc    ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00000000 )
-#define ERRFILE_timer_bios     ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00010000 )
+#define ERRFILE_timer_rdtsc   ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00000000 )
+#define ERRFILE_timer_bios    ( ERRFILE_ARCH | ERRFILE_DRIVER | 0x00010000 )
+
+#define ERRFILE_cpuid_cmd      ( ERRFILE_ARCH | ERRFILE_OTHER | 0x00000000 )
 
 /** @} */
 
diff --git a/src/arch/x86/include/ipxe/cpuid.h b/src/arch/x86/include/ipxe/cpuid.h
new file mode 100644 (file)
index 0000000..9705137
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef _IPXE_CPUID_H
+#define _IPXE_CPUID_H
+
+/** @file
+ *
+ * x86 CPU feature detection
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+
+/** An x86 CPU feature register set */
+struct x86_feature_registers {
+       /** Features returned via %ecx */
+       uint32_t ecx;
+       /** Features returned via %edx */
+       uint32_t edx;
+};
+
+/** x86 CPU features */
+struct x86_features {
+       /** Intel-defined features (%eax=0x00000001) */
+       struct x86_feature_registers intel;
+       /** AMD-defined features (%eax=0x80000001) */
+       struct x86_feature_registers amd;
+};
+
+/** CPUID support flag */
+#define CPUID_FLAG 0x00200000UL
+
+/** Get vendor ID and largest standard function */
+#define CPUID_VENDOR_ID 0x00000000UL
+
+/** Get standard features */
+#define CPUID_FEATURES 0x00000001UL
+
+/** Get largest extended function */
+#define CPUID_AMD_MAX_FN 0x80000000UL
+
+/** Extended function existence check */
+#define CPUID_AMD_CHECK 0x80000000UL
+
+/** Extended function existence check mask */
+#define CPUID_AMD_CHECK_MASK 0xffff0000UL
+
+/** Get extended features */
+#define CPUID_AMD_FEATURES 0x80000001UL
+
+extern void x86_features ( struct x86_features *features );
+
+#endif /* _IPXE_CPUID_H */
index 9c1df1f308e91391ed4f02f657610e03cc5183f6..eebd849b3e71804bf344752ef31d9df7138bbab9 100644 (file)
@@ -238,6 +238,9 @@ REQUIRE_OBJECT ( vlan_cmd );
 #ifdef REBOOT_CMD
 REQUIRE_OBJECT ( reboot_cmd );
 #endif
+#ifdef CPUID_CMD
+REQUIRE_OBJECT ( cpuid_cmd );
+#endif
 
 /*
  * Drag in miscellaneous objects
index b68186f1bb53a496334e76a6a65cda4ac2b72941..c52fca972f6832e4e8e632ec6bb75a5fd0f240c9 100644 (file)
@@ -36,5 +36,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define        SANBOOT_PROTO_FCP       /* Fibre Channel protocol */
 
 #define        REBOOT_CMD              /* Reboot command */
+#define        CPUID_CMD               /* x86 CPU feature detection command */
 
 #endif /* CONFIG_DEFAULTS_PCBIOS_H */