chiark / gitweb /
x86-model: New program, prints CPUID information.
authorMark Wooding <mdw@distorted.org.uk>
Thu, 30 Apr 2009 22:56:57 +0000 (23:56 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Thu, 30 Apr 2009 23:17:05 +0000 (00:17 +0100)
Makefile.am
configure.ac
debian/control
debian/inst
x86-model.1 [new file with mode: 0644]
x86-model.c [new file with mode: 0644]

index 25ac5e45e361d2e8098246393d03dec3c07aeab4..03d42f6052b4b0dbe85f09177c8fc895b37f0b01 100644 (file)
@@ -110,6 +110,14 @@ cdb_check_domain_LDADD      = -lcdb
 dist_man_MANS          += cdb-probe.1 cdb-check-domain.1
 endif
 
+## x86 model identification
+if X86
+bin_PROGRAMS           += x86-model
+x86_model_SOURCES       = x86-model.c
+x86_model_LDADD                 = $(mLib_LIBS)
+dist_man_MANS          += x86-model.1
+endif
+
 ###--------------------------------------------------------------------------
 ### Tools in scripts.
 
index dda3d4e9e40fa09e442af74b035dbf742780930e..814b686c469c0195971466e9b9d8de2b792efb1f 100644 (file)
@@ -30,6 +30,8 @@ AC_CONFIG_SRCDIR([shadowfix.in])
 AC_CONFIG_AUX_DIR([config])
 AM_INIT_AUTOMAKE([foreign])
 
+AC_CANONICAL_HOST
+
 dnl--------------------------------------------------------------------------
 dnl C programming environment.
 
@@ -57,6 +59,10 @@ PKG_CHECK_MODULES([catacomb], [catacomb >= 2.1.1],
                  [have_catacomb=yes], [have_catacomb=no])
 AM_CONDITIONAL([HAVE_CATACOMB], [test $have_catacomb = yes])
 
+## Processor type.
+case "$host_cpu" in i?86) x86=yes;; *) x86=no;; esac
+AM_CONDITIONAL([X86], [test $x86 = yes -a $GCC = yes])
+
 dnl--------------------------------------------------------------------------
 dnl Python, Perl and other scripting languages.
 
index 451354848a520bd191f3282251dbcd7c6f5c209a..a03ea221f28794165a17a76c4f733098640c86c8 100644 (file)
@@ -136,3 +136,9 @@ Description: Identify and fix problematic whitespace in text files.
  and fix problems such as trailing whitespace and spaces before tabs.
  It can safely update files in place, and could therefore be used as part
  of a commit hook.
+
+Package: x86-model
+Architecture: i386
+Section: utils
+Description: Shows basic model information about x86 processors.
+ The cpuid program is probably better for most people.
index ca8851d470cd6ff100c8325da837521e3bf2dd4b..7855b361f018408b1aaeb287c1022347dea397f0 100644 (file)
@@ -44,3 +44,5 @@ unfwd.1 nsict-mail /usr/share/man/man1
 xtitle xtitle /usr/bin
 z zz /usr/bin
 z.1 zz /usr/share/man/man1
+x86-model x86-model /usr/bin
+x86-model.1 x86-model /usr/share/man/man1
diff --git a/x86-model.1 b/x86-model.1
new file mode 100644 (file)
index 0000000..b363f6d
--- /dev/null
@@ -0,0 +1,75 @@
+.TH x86-model 1 "30 April 2009" "Edgeware tools"
+.SH NAME
+x86-model \- show x86 CPU model information and (a bit) more
+.SH SYNOPSIS
+.B x86-model
+.RB [ \-v ]
+.RB [ \-i \c
+.RB | \-d \c
+.RB |[ \-s ]
+.IR leaf ] \c
+.RB | \-x
+.IR leaf ]
+.SH DESCRIPTION
+The
+.b x86-model
+program shows basic information about the host's x86-based processor,
+gleaned from the CPUID instruction.  It doesn't work on other processors
+at all.  The
+.B \-v
+flag causes more detailed information to be output.
+.PP
+The CPUID instruction reads an index in the EAX register which selects a
+`leaf' of information; it sets the output registers EAX, EBX, ECX, and
+EDX, to the appropriate values for the selected leaf.
+.PP
+By default, or with
+.BR \-i ,
+it shows the `display family' and `display model' information for the
+processor, in the form
+.IB family _ model H
+which is used in the tables in Appendix C of Intel's optimization
+guide.  In verbose mode, the processor type, family, model and stepping
+are shown separately.
+.PP
+With the
+.B \-d
+option, all of the available CPUID information is dumped to standard
+output.  Each line has the form
+.IP
+.IB leaf :
+.I eax
+.I ebx
+.I ecx
+.I edx
+.PP
+Verbose mode makes no difference.
+.PP
+With the
+.B \-s
+option (or just a
+.I leaf
+index), prints the leaf of information selected by
+.IR leaf ,
+as four hexadecimal numbers separated by spaces.  In verbose mode, the
+output is written on four lines, labelled with the appropriate register
+names.
+.PP
+With the
+.B \-x
+option, the behaviour is as for
+.B \-s
+except that `extended function' information is selected by toggling bit
+31 of the leaf index.
+.PP
+If no option is given, but there is a command-line argument, then the
+behaviour is as for
+.B \-s
+with the leaf taken from the argument; otherwise the behaviour is as for
+.BR \-i .
+.SH SEE ALSO
+.BR cpuid (1).
+.PP
+.I "Intel 64 and IA-32 Architectures Software Developer's Manual"
+.br
+.I "Intel 64 and IA-32 Architectures Optimization Reference Manual"
diff --git a/x86-model.c b/x86-model.c
new file mode 100644 (file)
index 0000000..59640c7
--- /dev/null
@@ -0,0 +1,253 @@
+/* -*-c-*-
+ *
+ * Determine x86 CPU model number
+ *
+ * (c) 2009 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * 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
+ * (at your option) 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <mLib/mdwopt.h>
+#include <mLib/quis.h>
+#include <mLib/report.h>
+
+#if !defined(__GNUC__) || !defined(__i386__)
+#  error "This isn't going to work."
+#endif
+
+/*----- Data structures ---------------------------------------------------*/
+
+struct cpuid { unsigned eax, ebx, ecx, edx; };
+
+/*----- Main code ---------------------------------------------------------*/
+
+static inline void cpuid(unsigned leaf, struct cpuid *c)
+{
+  __asm__ ("cpuid"
+          : "=a" (c->eax),
+            "=b" (c->ebx),
+            "=c" (c->ecx),
+            "=d" (c->edx)
+          : "a" (leaf));
+}
+
+#define f_verbose 1u
+#define f_bogus 2u
+
+static void identify(unsigned f)
+{
+  struct cpuid c;
+  unsigned stepping, model, family, type, extmodel, extfamily;
+  unsigned dispfamily, dispmodel;
+
+  cpuid(1, &c);
+  stepping  = (c.eax >>  0) & 0x0f;
+  model     = (c.eax >>  4) & 0x0f;
+  family    = (c.eax >>  8) & 0x0f;
+  type      = (c.eax >> 12) & 0x03;
+  extmodel  = (c.eax >> 16) & 0x0f;
+  extfamily = (c.eax >> 20) & 0xff;
+
+  dispfamily = family + (family == 0x0f ? extfamily : 0);
+  dispmodel = model | (family == 0x06 || family == 0x0f ? extmodel << 4 : 0);
+
+  if (!(f & f_verbose))
+    printf("%02X_%02XH\n", dispfamily, dispmodel);
+  else {
+    printf("type = %d\n", type);
+    printf("family = %d", dispfamily);
+    if (family == 0x0f)
+      printf(" (base = %d, extended = %d)", family, extfamily);
+    putchar('\n');
+    printf("model = %d", dispmodel);
+    if (family == 0x06 || family == 0x0f)
+      printf(" (base = %d, extended = %d)", model, extmodel);
+    putchar('\n');
+    printf("stepping = %d\n", type);
+  }
+}
+
+static void dump(unsigned leaf)
+{
+  unsigned max;
+  struct cpuid c;
+
+  cpuid(leaf, &c);
+  max = c.eax;
+  for (;;) {
+    printf("%08x: %08x %08x %08x %08x\n", leaf, c.eax, c.ebx, c.ecx, c.edx);
+    leaf++;
+    if (leaf > max)
+      break;
+    cpuid(leaf, &c);
+  }
+}
+
+static void usage(FILE *fp)
+  { pquis(fp, "Usage: $ [-v] [-i | -d | [-s] LEAF | -x LEAF]\n");  }
+
+static void version(void)
+  { pquis(stdout, "$, version " VERSION ); }
+
+static void help(void)
+{
+  version(); putchar('\n'); usage(stdout);
+  pquis(stdout, "\n\
+Shows information about the host's processor.  You may find cpuid(1) more\n\
+enlightening.\n\
+\n\
+Options:\n\
+\n\
+-h, --help             This useless help text.\n\
+-V, --version          Program's version number.\n\
+-u, --usage            Short usage summary.\n\
+\n\
+-v, --verbose          Show more detailed information.\n\
+\n\
+-i, --identify         Show CPU display-model designation. [default]\n\
+-s, --show=LEAF                Show named leaf of CPUID data.\n\
+-x, --extended=LEAF    Show named extended leaf of CPUID data.\n\
+-d, --dump             Dump all CPUID information.\n");
+}
+
+int main(int argc, char *argv[])
+{
+  int i;
+  struct cpuid c;
+  unsigned f = 0;
+  unsigned mode = 0;
+  const char *leafstr = 0;
+  unsigned long leaf = -1;
+  char *q;
+
+  enum {
+    m_default,
+    m_identify,
+    m_dump,
+    m_show,
+    m_ext
+  };
+
+  ego(argv[0]);
+
+  for (;;) {
+    static const struct option opts[] = {
+      { "help",                0,              0,      'h' },
+      { "version",     0,              0,      'V' },
+      { "usage",       0,              0,      'u' },
+      { "verbose",     0,              0,      'v' },
+      { "identify",    0,              0,      'i' },
+      { "dump",                0,              0,      'd' },
+      { "show",                OPTF_ARGREQ,    0,      's' },
+      { "extended",    OPTF_ARGREQ,    0,      'x' },
+      { 0,             0,              0,      0 }
+    };
+
+    if ((i = mdwopt(argc, argv, "hVu" "v" "ids:x:", opts, 0, 0, 0)) < 0)
+      break;
+    switch (i) {
+      case 'h':
+       help();
+       exit(0);
+      case 'V':
+       version();
+       exit(0);
+      case 'u':
+       usage(stdout);
+       exit(0);
+      case 'v':
+       f |= f_verbose;
+       break;
+      case 'i':
+       if (mode) f |= f_bogus;
+       mode = m_identify;
+       break;
+      case 'd':
+       if (mode) f |= f_bogus;
+       mode = m_dump;
+       break;
+      case 's':
+       if (mode) f |= f_bogus;
+       mode = m_show;
+       leafstr = optarg;
+       break;
+      case 'x':
+       if (mode) f |= f_bogus;
+       mode = m_ext;
+       leafstr = optarg;
+       break;
+      default:
+       f |= f_bogus;
+       break;
+    }
+  }
+
+  argv += optind; argc -= optind;
+  if ((f & f_bogus) || argc > 1 || (mode && argc)) {
+    usage(stderr);
+    exit(EXIT_FAILURE);
+  }
+
+  if (!mode && argc) {
+    leafstr = argv[0];
+    mode = m_show;
+  }
+  if (leafstr) {
+    errno = 0;
+    leaf = strtoul(leafstr, &q, 0);
+    if (q == leafstr || *q || errno || leaf > 0xffffffff)
+      die(EXIT_FAILURE, "bad leaf value: %s", leafstr);
+  }
+
+  switch (mode) {
+    case m_default:
+    case m_identify:
+      identify(f);
+      break;
+    case m_ext:
+      leaf ^= 0x80000000;
+      /* fall through */
+    case m_show:
+      cpuid(leaf, &c);
+      if (!(f & f_verbose))
+       printf("%08x %08x %08x %08x\n", c.eax, c.ebx, c.ecx, c.edx);
+      else {
+       printf("EAX = %08x\n", c.eax);
+       printf("EBX = %08x\n", c.ebx);
+       printf("ECX = %08x\n", c.ecx);
+       printf("EDX = %08x\n", c.edx);
+      }
+      break;
+    case m_dump:
+      dump(0);
+      dump(0x80000000);
+      break;
+    default:
+      abort();
+  }
+
+  return (0);
+}
+
+/*----- That's all, folks -------------------------------------------------*/