chiark / gitweb /
hush.in: Close extraneous file descriptors when running the command.
[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
35#if !defined(__GNUC__) || !defined(__i386__)
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{
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
58static 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');
e72ffec7 87 printf("stepping = %d\n", stepping);
92f7c002
MW
88 }
89}
90
91static 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
107static void usage(FILE *fp)
108 { pquis(fp, "Usage: $ [-v] [-i | -d | [-s] LEAF | -x LEAF]\n"); }
109
110static void version(void)
111 { pquis(stdout, "$, version " VERSION ); }
112
113static void help(void)
114{
115 version(); putchar('\n'); usage(stdout);
116 pquis(stdout, "\n\
117Shows information about the host's processor. You may find cpuid(1) more\n\
118enlightening.\n\
119\n\
120Options:\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
134int 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 -------------------------------------------------*/