Skip to content

Commit c975b9e

Browse files
H. Peter AnvinJin Kyu Song
authored andcommitted
Add cpuid tool
It enumerates CPU identification and feature information of a specific CPU. CPUID kernel module is required for retrieving information. Signed-off-by: Jin Kyu Song <jin.kyu.song@intel.com>
1 parent b76e95b commit c975b9e

File tree

2 files changed

+187
-1
lines changed

2 files changed

+187
-1
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ CC = gcc -Wall
1818
CFLAGS = -g -O2 -fomit-frame-pointer -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64
1919
LDFLAGS =
2020

21-
BIN = wrmsr rdmsr
21+
BIN = wrmsr rdmsr cpuid
2222

2323
sbindir = /usr/sbin
2424

cpuid.c

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
/*
2+
* Utility to read CPUIDs from x86 processors
3+
* Copyright (c) 2013, Intel Corporation.
4+
*
5+
* This program is free software; you can redistribute it and/or modify it
6+
* under the terms and conditions of the GNU General Public License,
7+
* version 2, as published by the Free Software Foundation.
8+
*
9+
* This program is distributed in the hope it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12+
* more details.
13+
*
14+
* You should have received a copy of the GNU General Public License along with
15+
* this program; if not, write to the Free Software Foundation, Inc.,
16+
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
17+
*
18+
*/
19+
20+
#include <stdio.h>
21+
#include <ctype.h>
22+
#include <stdbool.h>
23+
#include <stdint.h>
24+
#include <unistd.h>
25+
#include <fcntl.h>
26+
#include <stdlib.h>
27+
#include <string.h>
28+
#include <errno.h>
29+
30+
struct cpuid {
31+
uint32_t eax, ebx, ecx, edx;
32+
};
33+
34+
static int cpuid(int cpu, uint32_t leaf, uint32_t subleaf, struct cpuid *data)
35+
{
36+
static int fd = -1;
37+
static int last_cpu;
38+
off_t offset = leaf + ((off_t) subleaf << 32);
39+
40+
if (fd < 0 || last_cpu != cpu) {
41+
char devstr[64];
42+
if (fd >= 0)
43+
close(fd);
44+
snprintf(devstr, sizeof devstr, "/dev/cpu/%d/cpuid", cpu);
45+
fd = open(devstr, O_RDONLY);
46+
if (fd < 0) {
47+
if (errno == ENXIO) {
48+
fprintf(stderr, "cpuid: No CPU %d\n", cpu);
49+
exit(2);
50+
} else if (errno == EIO) {
51+
fprintf(stderr,
52+
"cpuid: CPU %d doesn't support cpuid\n",
53+
cpu);
54+
exit(3);
55+
} else {
56+
perror("cpuid: open");
57+
exit(127);
58+
}
59+
}
60+
last_cpu = cpu;
61+
}
62+
return pread(fd, data, sizeof(*data), offset) == sizeof(*data) ? 0 : -1;
63+
}
64+
65+
static char *make_string(uint32_t val)
66+
{
67+
static char string[5] = "xxxx";
68+
int i, ch;
69+
70+
for (i = 0; i < 4; i++) {
71+
ch = val & 0xff;
72+
string[i] = isprint(ch) ? ch : '.';
73+
val >>= 8;
74+
}
75+
76+
return string;
77+
}
78+
79+
static void print_cpuid_level(uint32_t leaf, uint32_t subleaf,
80+
struct cpuid *lvl)
81+
{
82+
printf("%08x %08x: ", leaf, subleaf);
83+
printf("%08x %s ", lvl->eax, make_string(lvl->eax));
84+
printf("%08x %s ", lvl->ebx, make_string(lvl->ebx));
85+
printf("%08x %s ", lvl->ecx, make_string(lvl->ecx));
86+
printf("%08x %s\n", lvl->edx, make_string(lvl->edx));
87+
}
88+
89+
static void dump_cpuid_leaf(int cpu, uint32_t leaf)
90+
{
91+
struct cpuid lvl, lastlvl, lvl0;
92+
uint32_t subleaf;
93+
94+
cpuid(cpu, leaf, 0, &lvl0);
95+
print_cpuid_level(leaf, 0, &lvl0);
96+
97+
/*
98+
* There is no standard mechanism for enumerating the number of
99+
* subleaves, this is a heuristic...
100+
*/
101+
lastlvl = lvl0;
102+
103+
for (subleaf = 1; subleaf != 0; subleaf++) {
104+
if (cpuid(cpu, leaf, subleaf, &lvl))
105+
return;
106+
107+
switch (leaf) {
108+
case 4:
109+
if ((lvl.eax & 0x1f) == 0
110+
|| !memcmp(&lvl, &lastlvl, sizeof lvl))
111+
return;
112+
break;
113+
114+
case 7:
115+
if (subleaf >= lvl0.eax)
116+
return;
117+
break;
118+
119+
case 0xb:
120+
if ((lvl.ecx & ~0xff) == 0)
121+
return;
122+
123+
case 0xd:
124+
if ((lvl.eax | lvl.ebx | lvl.ecx | lvl.edx) == 0)
125+
return;
126+
127+
default:
128+
/* Generic, anticipatory rules */
129+
/* Exclude ecx here for levels which return the initial ecx value */
130+
if ((lvl.eax | lvl.ebx | lvl.ecx | lvl.edx) == 0)
131+
return;
132+
133+
if (!memcmp(&lvl, &lvl0, sizeof lvl))
134+
return;
135+
break;
136+
}
137+
138+
print_cpuid_level(leaf, subleaf, &lvl);
139+
140+
lastlvl = lvl;
141+
}
142+
}
143+
144+
static void dump_levels(int cpu, uint32_t region)
145+
{
146+
static struct cpuid invalid_leaf;
147+
struct cpuid max;
148+
uint32_t n;
149+
150+
if (cpuid(cpu, region, 0, &max))
151+
return;
152+
153+
/*
154+
* Intel processors may return the last group 0 CPUID leaf instead
155+
* all zero for a not-present level
156+
*/
157+
if (region == 0) {
158+
cpuid(cpu, max.eax + 1, 0, &invalid_leaf);
159+
} else {
160+
if (!memcmp(&max, &invalid_leaf, sizeof(struct cpuid)))
161+
return;
162+
}
163+
164+
if ((max.eax & 0xffff0000) == region) {
165+
for (n = region; n <= max.eax; n++) {
166+
dump_cpuid_leaf(cpu, n);
167+
}
168+
}
169+
}
170+
171+
int main(int argc, char *argv[])
172+
{
173+
int cpu;
174+
uint32_t n;
175+
176+
cpu = (argc > 1) ? atoi(argv[1]) : 0;
177+
178+
printf
179+
("Leaf Subleaf EAX EBX ECX EDX \n");
180+
181+
for (n = 0; n <= 0xffff; n++) {
182+
dump_levels(cpu, n << 16);
183+
}
184+
185+
return 0;
186+
}

0 commit comments

Comments
 (0)