chiark / gitweb /
space.1: Fix up the manpage a bit.
[misc] / x86-model.c
1 /* -*-c-*-
2  *
3  * Determine x86 CPU model number
4  *
5  * (c) 2009 Mark Wooding
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23  */
24
25 /*----- Header files ------------------------------------------------------*/
26
27 #include <errno.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30
31 #include <mLib/mdwopt.h>
32 #include <mLib/quis.h>
33 #include <mLib/report.h>
34
35 #if !defined(__GNUC__) || !defined(__i386__)
36 #  error "This isn't going to work."
37 #endif
38
39 /*----- Data structures ---------------------------------------------------*/
40
41 struct cpuid { unsigned eax, ebx, ecx, edx; };
42
43 /*----- Main code ---------------------------------------------------------*/
44
45 static inline void cpuid(unsigned leaf, struct cpuid *c)
46 {
47   __asm__ ("cpuid"
48            : "=a" (c->eax),
49              "=b" (c->ebx),
50              "=c" (c->ecx),
51              "=d" (c->edx)
52            : "a" (leaf));
53 }
54
55 #define f_verbose 1u
56 #define f_bogus 2u
57
58 static void identify(unsigned f)
59 {
60   struct cpuid c;
61   unsigned stepping, model, family, type, extmodel, extfamily;
62   unsigned dispfamily, dispmodel;
63
64   cpuid(1, &c);
65   stepping  = (c.eax >>  0) & 0x0f;
66   model     = (c.eax >>  4) & 0x0f;
67   family    = (c.eax >>  8) & 0x0f;
68   type      = (c.eax >> 12) & 0x03;
69   extmodel  = (c.eax >> 16) & 0x0f;
70   extfamily = (c.eax >> 20) & 0xff;
71
72   dispfamily = family + (family == 0x0f ? extfamily : 0);
73   dispmodel = model | (family == 0x06 || family == 0x0f ? extmodel << 4 : 0);
74
75   if (!(f & f_verbose))
76     printf("%02X_%02XH\n", dispfamily, dispmodel);
77   else {
78     printf("type = %d\n", type);
79     printf("family = %d", dispfamily);
80     if (family == 0x0f)
81       printf(" (base = %d, extended = %d)", family, extfamily);
82     putchar('\n');
83     printf("model = %d", dispmodel);
84     if (family == 0x06 || family == 0x0f)
85       printf(" (base = %d, extended = %d)", model, extmodel);
86     putchar('\n');
87     printf("stepping = %d\n", type);
88   }
89 }
90
91 static void dump(unsigned leaf)
92 {
93   unsigned max;
94   struct cpuid c;
95
96   cpuid(leaf, &c);
97   max = c.eax;
98   for (;;) {
99     printf("%08x: %08x %08x %08x %08x\n", leaf, c.eax, c.ebx, c.ecx, c.edx);
100     leaf++;
101     if (leaf > max)
102       break;
103     cpuid(leaf, &c);
104   }
105 }
106
107 static void usage(FILE *fp)
108   { pquis(fp, "Usage: $ [-v] [-i | -d | [-s] LEAF | -x LEAF]\n");  }
109
110 static void version(void)
111   { pquis(stdout, "$, version " VERSION ); }
112
113 static void help(void)
114 {
115   version(); putchar('\n'); usage(stdout);
116   pquis(stdout, "\n\
117 Shows information about the host's processor.  You may find cpuid(1) more\n\
118 enlightening.\n\
119 \n\
120 Options:\n\
121 \n\
122 -h, --help              This useless help text.\n\
123 -V, --version           Program's version number.\n\
124 -u, --usage             Short usage summary.\n\
125 \n\
126 -v, --verbose           Show more detailed information.\n\
127 \n\
128 -i, --identify          Show CPU display-model designation. [default]\n\
129 -s, --show=LEAF         Show named leaf of CPUID data.\n\
130 -x, --extended=LEAF     Show named extended leaf of CPUID data.\n\
131 -d, --dump              Dump all CPUID information.\n");
132 }
133
134 int main(int argc, char *argv[])
135 {
136   int i;
137   struct cpuid c;
138   unsigned f = 0;
139   unsigned mode = 0;
140   const char *leafstr = 0;
141   unsigned long leaf = -1;
142   char *q;
143
144   enum {
145     m_default,
146     m_identify,
147     m_dump,
148     m_show,
149     m_ext
150   };
151
152   ego(argv[0]);
153
154   for (;;) {
155     static const struct option opts[] = {
156       { "help",         0,              0,      'h' },
157       { "version",      0,              0,      'V' },
158       { "usage",        0,              0,      'u' },
159       { "verbose",      0,              0,      'v' },
160       { "identify",     0,              0,      'i' },
161       { "dump",         0,              0,      'd' },
162       { "show",         OPTF_ARGREQ,    0,      's' },
163       { "extended",     OPTF_ARGREQ,    0,      'x' },
164       { 0,              0,              0,      0 }
165     };
166
167     if ((i = mdwopt(argc, argv, "hVu" "v" "ids:x:", opts, 0, 0, 0)) < 0)
168       break;
169     switch (i) {
170       case 'h':
171         help();
172         exit(0);
173       case 'V':
174         version();
175         exit(0);
176       case 'u':
177         usage(stdout);
178         exit(0);
179       case 'v':
180         f |= f_verbose;
181         break;
182       case 'i':
183         if (mode) f |= f_bogus;
184         mode = m_identify;
185         break;
186       case 'd':
187         if (mode) f |= f_bogus;
188         mode = m_dump;
189         break;
190       case 's':
191         if (mode) f |= f_bogus;
192         mode = m_show;
193         leafstr = optarg;
194         break;
195       case 'x':
196         if (mode) f |= f_bogus;
197         mode = m_ext;
198         leafstr = optarg;
199         break;
200       default:
201         f |= f_bogus;
202         break;
203     }
204   }
205
206   argv += optind; argc -= optind;
207   if ((f & f_bogus) || argc > 1 || (mode && argc)) {
208     usage(stderr);
209     exit(EXIT_FAILURE);
210   }
211
212   if (!mode && argc) {
213     leafstr = argv[0];
214     mode = m_show;
215   }
216   if (leafstr) {
217     errno = 0;
218     leaf = strtoul(leafstr, &q, 0);
219     if (q == leafstr || *q || errno || leaf > 0xffffffff)
220       die(EXIT_FAILURE, "bad leaf value: %s", leafstr);
221   }
222
223   switch (mode) {
224     case m_default:
225     case m_identify:
226       identify(f);
227       break;
228     case m_ext:
229       leaf ^= 0x80000000;
230       /* fall through */
231     case m_show:
232       cpuid(leaf, &c);
233       if (!(f & f_verbose))
234         printf("%08x %08x %08x %08x\n", c.eax, c.ebx, c.ecx, c.edx);
235       else {
236         printf("EAX = %08x\n", c.eax);
237         printf("EBX = %08x\n", c.ebx);
238         printf("ECX = %08x\n", c.ecx);
239         printf("EDX = %08x\n", c.edx);
240       }
241       break;
242     case m_dump:
243       dump(0);
244       dump(0x80000000);
245       break;
246     default:
247       abort();
248   }
249
250   return (0);
251 }
252
253 /*----- That's all, folks -------------------------------------------------*/