mtimeout.1: Use correct dash for number ranges.
[misc] / x86-model.c
CommitLineData
92f7c002
MW
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
8fc36470 35#if !defined(__GNUC__) || (!defined(__i386__) && !defined(__amd64__))
92f7c002
MW
36# error "This isn't going to work."
37#endif
38
39/*----- Data structures ---------------------------------------------------*/
40
41struct cpuid { unsigned eax, ebx, ecx, edx; };
42
43/*----- Main code ---------------------------------------------------------*/
44
45static inline void cpuid(unsigned leaf, struct cpuid *c)
46{
8fc36470 47
92f7c002
MW
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
59static 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');
e72ffec7 88 printf("stepping = %d\n", stepping);
92f7c002
MW
89 }
90}
91
92static 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
108static void usage(FILE *fp)
109 { pquis(fp, "Usage: $ [-v] [-i | -d | [-s] LEAF | -x LEAF]\n"); }
110
111static void version(void)
112 { pquis(stdout, "$, version " VERSION ); }
113
114static void help(void)
115{
116 version(); putchar('\n'); usage(stdout);
117 pquis(stdout, "\n\
118Shows information about the host's processor. You may find cpuid(1) more\n\
119enlightening.\n\
120\n\
121Options:\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
135int 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 -------------------------------------------------*/