chiark / gitweb /
hush.in: Use `$' prefixes on variables in arithmetic expansions.
[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__) && !defined(__amd64__))
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
48   __asm__ ("cpuid"
49            : "=a" (c->eax),
50              "=b" (c->ebx),
51              "=c" (c->ecx),
52              "=d" (c->edx)
53            : "a" (leaf));
54 }
55
56 #define f_verbose 1u
57 #define f_bogus 2u
58
59 static void identify(unsigned f)
60 {
61   struct cpuid c;
62   unsigned stepping, model, family, type, extmodel, extfamily;
63   unsigned dispfamily, dispmodel;
64
65   cpuid(1, &c);
66   stepping  = (c.eax >>  0) & 0x0f;
67   model     = (c.eax >>  4) & 0x0f;
68   family    = (c.eax >>  8) & 0x0f;
69   type      = (c.eax >> 12) & 0x03;
70   extmodel  = (c.eax >> 16) & 0x0f;
71   extfamily = (c.eax >> 20) & 0xff;
72
73   dispfamily = family + (family == 0x0f ? extfamily : 0);
74   dispmodel = model | (family == 0x06 || family == 0x0f ? extmodel << 4 : 0);
75
76   if (!(f & f_verbose))
77     printf("%02X_%02XH\n", dispfamily, dispmodel);
78   else {
79     printf("type = %d\n", type);
80     printf("family = %d", dispfamily);
81     if (family == 0x0f)
82       printf(" (base = %d, extended = %d)", family, extfamily);
83     putchar('\n');
84     printf("model = %d", dispmodel);
85     if (family == 0x06 || family == 0x0f)
86       printf(" (base = %d, extended = %d)", model, extmodel);
87     putchar('\n');
88     printf("stepping = %d\n", stepping);
89   }
90 }
91
92 static void dump(unsigned leaf)
93 {
94   unsigned max;
95   struct cpuid c;
96
97   cpuid(leaf, &c);
98   max = c.eax;
99   for (;;) {
100     printf("%08x: %08x %08x %08x %08x\n", leaf, c.eax, c.ebx, c.ecx, c.edx);
101     leaf++;
102     if (leaf > max)
103       break;
104     cpuid(leaf, &c);
105   }
106 }
107
108 static void usage(FILE *fp)
109   { pquis(fp, "Usage: $ [-v] [-i | -d | [-s] LEAF | -x LEAF]\n");  }
110
111 static void version(void)
112   { pquis(stdout, "$, version " VERSION ); }
113
114 static void help(void)
115 {
116   version(); putchar('\n'); usage(stdout);
117   pquis(stdout, "\n\
118 Shows information about the host's processor.  You may find cpuid(1) more\n\
119 enlightening.\n\
120 \n\
121 Options:\n\
122 \n\
123 -h, --help              This useless help text.\n\
124 -V, --version           Program's version number.\n\
125 -u, --usage             Short usage summary.\n\
126 \n\
127 -v, --verbose           Show more detailed information.\n\
128 \n\
129 -i, --identify          Show CPU display-model designation. [default]\n\
130 -s, --show=LEAF         Show named leaf of CPUID data.\n\
131 -x, --extended=LEAF     Show named extended leaf of CPUID data.\n\
132 -d, --dump              Dump all CPUID information.\n");
133 }
134
135 int main(int argc, char *argv[])
136 {
137   int i;
138   struct cpuid c;
139   unsigned f = 0;
140   unsigned mode = 0;
141   const char *leafstr = 0;
142   unsigned long leaf = -1;
143   char *q;
144
145   enum {
146     m_default,
147     m_identify,
148     m_dump,
149     m_show,
150     m_ext
151   };
152
153   ego(argv[0]);
154
155   for (;;) {
156     static const struct option opts[] = {
157       { "help",         0,              0,      'h' },
158       { "version",      0,              0,      'V' },
159       { "usage",        0,              0,      'u' },
160       { "verbose",      0,              0,      'v' },
161       { "identify",     0,              0,      'i' },
162       { "dump",         0,              0,      'd' },
163       { "show",         OPTF_ARGREQ,    0,      's' },
164       { "extended",     OPTF_ARGREQ,    0,      'x' },
165       { 0,              0,              0,      0 }
166     };
167
168     if ((i = mdwopt(argc, argv, "hVu" "v" "ids:x:", opts, 0, 0, 0)) < 0)
169       break;
170     switch (i) {
171       case 'h':
172         help();
173         exit(0);
174       case 'V':
175         version();
176         exit(0);
177       case 'u':
178         usage(stdout);
179         exit(0);
180       case 'v':
181         f |= f_verbose;
182         break;
183       case 'i':
184         if (mode) f |= f_bogus;
185         mode = m_identify;
186         break;
187       case 'd':
188         if (mode) f |= f_bogus;
189         mode = m_dump;
190         break;
191       case 's':
192         if (mode) f |= f_bogus;
193         mode = m_show;
194         leafstr = optarg;
195         break;
196       case 'x':
197         if (mode) f |= f_bogus;
198         mode = m_ext;
199         leafstr = optarg;
200         break;
201       default:
202         f |= f_bogus;
203         break;
204     }
205   }
206
207   argv += optind; argc -= optind;
208   if ((f & f_bogus) || argc > 1 || (mode && argc)) {
209     usage(stderr);
210     exit(EXIT_FAILURE);
211   }
212
213   if (!mode && argc) {
214     leafstr = argv[0];
215     mode = m_show;
216   }
217   if (leafstr) {
218     errno = 0;
219     leaf = strtoul(leafstr, &q, 0);
220     if (q == leafstr || *q || errno || leaf > 0xffffffff)
221       die(EXIT_FAILURE, "bad leaf value: %s", leafstr);
222   }
223
224   switch (mode) {
225     case m_default:
226     case m_identify:
227       identify(f);
228       break;
229     case m_ext:
230       leaf ^= 0x80000000;
231       /* fall through */
232     case m_show:
233       cpuid(leaf, &c);
234       if (!(f & f_verbose))
235         printf("%08x %08x %08x %08x\n", c.eax, c.ebx, c.ecx, c.edx);
236       else {
237         printf("EAX = %08x\n", c.eax);
238         printf("EBX = %08x\n", c.ebx);
239         printf("ECX = %08x\n", c.ecx);
240         printf("EDX = %08x\n", c.edx);
241       }
242       break;
243     case m_dump:
244       dump(0);
245       dump(0x80000000);
246       break;
247     default:
248       abort();
249   }
250
251   return (0);
252 }
253
254 /*----- That's all, folks -------------------------------------------------*/