--- /dev/null
+.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"
--- /dev/null
+/* -*-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 -------------------------------------------------*/