xref: /aosp_15_r20/external/coreboot/util/msrtool/msrtool.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <errno.h>
11 #include <pci/pci.h>
12 
13 #include "msrtool.h"
14 
15 #define DEFAULT_CPU 0
16 static uint8_t cpu = DEFAULT_CPU;
17 
18 uint8_t targets_found = 0;
19 const struct targetdef **targets = NULL;
20 const struct sysdef *sys = NULL;
21 uint8_t reserved = 0, verbose = 0, quiet = 0;
22 
23 struct pci_access *pacc = NULL;
24 
25 static struct targetdef alltargets[] = {
26 	{ "geodegx2", "AMD Geode(tm) GX2", geodegx2_probe, geodegx2_msrs },
27 	{ "geodelx", "AMD Geode(tm) LX", geodelx_probe, geodelx_msrs },
28 	{ "cs5536", "AMD Geode(tm) CS5536", cs5536_probe, cs5536_msrs },
29 	{ "K8", "AMD K8 Family", k8_probe, k8_msrs },
30 	{ "via_c7", "VIA Esther processor, C7", via_c7_probe, via_c7_msrs },
31 	{ "intel_pentium3_early", "Intel Pentium III family", intel_pentium3_early_probe, intel_pentium3_early_msrs },
32 	{ "intel_pentium3", "Intel Pentium III Xeon Processor, Intel Pentium III Processor", intel_pentium3_probe, intel_pentium3_msrs },
33 	{ "intel_core1", "Intel Core Duo, Intel Core Solo processors", intel_core1_probe, intel_core1_msrs },
34 	{ "intel_core2_early", "Intel Xeon Processor 3000, 3200, 5100, 5300, 7300 series, Intel Core 2 Quad processor 6000 series, Intel Core 2 Extreme 6000	series, Intel Core 2 Duo 4000, 5000, 6000, 7000 series processors, Intel Pentium dual-core processors", intel_core2_early_probe, intel_core2_early_msrs },
35 	{ "intel_core2_later", "Intel Xeon Processor 5200, 5400 series, Intel Core 2 Quad	processors 8000, 9000 series", intel_core2_later_probe, intel_core2_later_msrs },
36 	{ "intel_pentium4_early", "Intel Xeon Processor, Intel Xeon Processor MP, Intel Pentium 4 processors", intel_pentium4_early_probe, intel_pentium4_early_msrs },
37 	{ "intel_pentium4_later", "Intel Xeon Processor, Intel Xeon Processor MP, Intel Pentium 4, Pentium D processors", intel_pentium4_later_probe, intel_pentium4_later_msrs },
38 	{ "intel_pentium_d", "Intel Pentium D processors", intel_pentium_d_probe, intel_pentium_d_msrs },
39 	{ "intel_nehalem", "Intel Core i5, i7 Processors, Intel Xeon Processor 3400, 3500, 5500, based on Nehalem architecture", intel_nehalem_probe, intel_nehalem_msrs },
40 	{ "intel_atom", "Intel Atom Processors, N450", intel_atom_probe, intel_atom_msrs },
41 	{ TARGET_EOT }
42 };
43 
44 static struct sysdef allsystems[] = {
45 	{ "linux", "Linux with /dev/cpu/*/msr", linux_probe, linux_open, linux_close, linux_rdmsr },
46 	{ "darwin", "Mac OS X with DirectHW", darwin_probe, darwin_open, darwin_close, darwin_rdmsr },
47 	{ "freebsd", "FreeBSD with /dev/cpuctl*", freebsd_probe, freebsd_open, freebsd_close, freebsd_rdmsr },
48 	{ SYSTEM_EOT }
49 };
50 
syntax(char * argv[])51 static void syntax(char *argv[]) {
52 	printf("syntax: %s [-hvqrkl] [-c cpu] [-m system] [-t target ...]\n", argv[0]);
53 	printf("\t [-i addr=hi[:]lo] | [-s file] | [-d [:]file] | addr...\n");
54 	printf("  -h\t show this help text\n");
55 	printf("  -v\t be verbose\n");
56 	printf("  -q\t be quiet (overrides -v)\n");
57 	printf("  -r\t include [Reserved] values\n");
58 	printf("  -k\t list all known systems and targets\n");
59 	printf("  -l\t list MSRs and bit fields for current target(s) (-kl for ALL targets!)\n");
60 	printf("  -c\t access MSRs on the specified CPU, default=%d\n", DEFAULT_CPU);
61 	printf("  -m\t force a system, e.g: -m linux\n");
62 	printf("  -t\t force a target, can be used multiple times, e.g: -t geodelx -t cs5536\n");
63 	printf("  -i\t immediate mode\n");
64 	printf("\t decode hex addr=hi:lo for the target without reading hw value\n");
65 	printf("\t e.g: -i 4c00000f=f2f100ff56960004\n");
66 	printf("  -s\t stream mode\n");
67 	printf("\t read one MSR address per line and append current hw value to the line\n");
68 	printf("\t use the filename - for stdin/stdout\n");
69 	printf("\t using -l -s ignores input and will output all MSRs with values\n");
70 	printf("  -d\t diff mode\n");
71 	printf("\t read one address and value per line and compare with current hw value,\n");
72 	printf("\t printing differences to stdout. use the filename - to read from stdin\n");
73 	printf("\t use :file or :- to reverse diff, normally hw values are considered new\n");
74 	printf("  addr.. direct mode, read and decode values for the given MSR address(es)\n");
75 }
76 
add_target(const struct targetdef * t)77 static void *add_target(const struct targetdef *t) {
78 	void *tmp;
79 	tmp = realloc(targets, (targets_found + 2) * sizeof(struct targetdef *));
80 	if (NULL == tmp) {
81 		perror("realloc");
82 		return tmp;
83 	}
84 	targets = tmp;
85 	targets[targets_found++] = t;
86 	targets[targets_found] = NULL;
87 	return targets;
88 }
89 
found_system(void)90 static int found_system(void) {
91 	if (!sys || (sys && !sys->name)) {
92 		fprintf(stderr, "Unable to detect the current operating system!\n");
93 		fprintf(stderr, "On Linux, please run 'modprobe msr' and try again.\n");
94 		fprintf(stderr, "Please send a report or patch to [email protected]. Thanks for your help!\n");
95 		fprintf(stderr, "\n");
96 	}
97 	return (sys && sys->name);
98 }
99 
do_stream(const char * streamfn,uint8_t ignoreinput)100 int do_stream(const char *streamfn, uint8_t ignoreinput) {
101 	char tmpfn[20], line[256];
102 	uint8_t tn;
103 	size_t start, len;
104 	int ret = 1;
105 	int fdout = -1;
106 	FILE *fin = NULL, *fout = NULL;
107 	uint32_t addr, linenum;
108 	struct msr m = MSR1(0);
109 
110 	if (0 == strcmp(streamfn, "-")) {
111 		fin = stdin;
112 		fout = stdout;
113 	} else {
114 		if (!ignoreinput) {
115 			if (NULL == (fin = fopen(streamfn, "r"))) {
116 				perror("fopen()");
117 				return 1;
118 			}
119 			if (snprintf(tmpfn, sizeof(tmpfn), "msrtoolXXXXXX") >= sizeof(tmpfn)) {
120 				perror("snprintf");
121 				return 1;
122 			}
123 			if (-1 == (fdout = mkstemp(tmpfn))) {
124 				perror("mkstemp");
125 				return 1;
126 			}
127 			if (NULL == (fout = fdopen(fdout, "w"))) {
128 				perror("fdopen");
129 				return 1;
130 			}
131 		} else {
132 			if (NULL == (fout = fopen(streamfn, "w"))) {
133 				perror("fopen");
134 				return 1;
135 			}
136 		}
137 	}
138 
139 	if (!found_system())
140 		goto done;
141 	if (!sys->open(cpu, SYS_RDONLY))
142 		goto done;
143 	if (ignoreinput) {
144 		for (tn = 0; tn < targets_found; tn++)
145 			if (dumpmsrdefsvals(fout, targets[tn], cpu)) {
146 				ret = 1;
147 				break;
148 			}
149 	} else {
150 		for (linenum = 1; NULL != fgets(line, sizeof(line), fin); ++linenum) {
151 			start = (0 == strncmp("0x", line, 2)) ? 2 : 0;
152 			if (1 == sscanf(line + start, "%8x", &addr)) {
153 				if (!sys->rdmsr(cpu, addr, &m))
154 					goto done;
155 				fprintf(fout, "0x%08x 0x%08x%08x\n", addr, m.hi, m.lo);
156 				continue;
157 			}
158 			while (1) {
159 				fprintf(fout, "%s", line);
160 				len = strlen(line);
161 				if (NULL != strchr("\r\n", line[len - 1]))
162 					break;
163 				if (NULL == fgets(line, sizeof(line), fin))
164 					goto read_done;
165 			}
166 		}
167 read_done:
168 		if (!feof(fin)) {
169 			fprintf(stderr, "%s:%d: fgets: %s\n", streamfn, linenum, strerror(errno));
170 			goto done;
171 		}
172 	}
173 	ret = 0;
174 done:
175 	sys->close(cpu);
176 	if (strcmp(streamfn, "-")) {
177 		if (ret)
178 			unlink(tmpfn);
179 		else if (!ignoreinput)
180 			rename(tmpfn, streamfn);
181 	}
182 	if (!ignoreinput)
183 		fclose(fin);
184 	fclose(fout);
185 	return ret;
186 }
187 
do_diff(const char * difffn)188 int do_diff(const char *difffn) {
189 	char tmpfn[20], line[512], *m1start, *m2start;
190 	size_t len;
191 	int ret = 1, tmp, m1pos, sys_opened = 0;
192 	FILE *fin = NULL, *fout = stdout;
193 	uint8_t rev = 0;
194 	uint32_t addr, linenum;
195 	struct msr m1 = MSR1(0), m2 = MSR1(0);
196 
197 	if (':' == difffn[0]) {
198 		rev = 1;
199 		++difffn;
200 	}
201 	if (0 == strcmp(difffn, "-"))
202 		fin = stdin;
203 	else if (NULL == (fin = fopen(difffn, "r"))) {
204 		perror("fopen()");
205 		return 1;
206 	}
207 
208 	for (linenum = 1; NULL != fgets(line, sizeof(line), fin); ++linenum) {
209 		tmp = strncmp("0x", line, 2) ? 0 : 2;
210 		if (sscanf(line + tmp, "%8x %n%*x", &addr, &m1pos) < 1)
211 			continue;
212 		m1start = line + tmp + m1pos;
213 		for (len = strlen(m1start) - 1; NULL != strchr("\r\n", m1start[len]); --len)
214 			m1start[len] = 0;
215 		if (!str2msr(m1start, &m1, &m2start)) {
216 			fprintf(stderr, "%s:%d: invalid MSR1 value '%s'\n", difffn, linenum, m1start);
217 			continue;
218 		}
219 		while (' ' == *m2start)
220 			++m2start;
221 		if (!str2msr(m2start, &m2, NULL)) {
222 			fprintf(stderr, "%s:%d: invalid MSR2 value '%s' - reading from hardware!\n", difffn, linenum, m2start);
223 			if (!sys_opened) {
224 				if (!found_system())
225 					goto done;
226 				sys_opened = sys->open(cpu, SYS_RDONLY);
227 				if (!sys_opened)
228 					goto done;
229 			}
230 			if (!sys->rdmsr(cpu, addr, &m2))
231 				goto done;
232 		}
233 		if (diff_msr(fout, addr, rev ? m2 : m1, rev ? m1 : m2))
234 			fprintf(fout, "\n");
235 	}
236 	if (!feof(fin))
237 		fprintf(stderr, "%s:%d: fgets: %s\n", difffn, linenum, strerror(errno));
238 	else
239 		ret = 0;
240 done:
241 	if (sys_opened)
242 		sys->close(cpu);
243 	if (strcmp(difffn, "-")) {
244 		if (ret)
245 			unlink(tmpfn);
246 		else
247 			rename(tmpfn, difffn);
248 		fclose(fin);
249 		fclose(fout);
250 	}
251 	return ret;
252 }
253 
main(int argc,char * argv[])254 int main(int argc, char *argv[]) {
255 	char c;
256 	int ret = 1;
257 	const struct sysdef *s;
258 	const struct targetdef *t;
259 	uint8_t tn, listmsrs = 0, listknown = 0, input = 0;
260 	uint32_t addr = 0;
261 	const char *streamfn = NULL, *difffn = NULL;
262 	struct msr msrval = MSR2(-1, -1);
263 	while ((c = getopt(argc, argv, "hqvrklc:m:t:a:i:s:d:")) != -1)
264 		switch (c) {
265 		case 'h':
266 			syntax(argv);
267 			return 0;
268 		case 'q':
269 			quiet = 1;
270 			break;
271 		case 'v':
272 			++verbose;
273 			break;
274 		case 'r':
275 			reserved = 1;
276 			break;
277 		case 'k':
278 			listknown = 1;
279 			break;
280 		case 'l':
281 			listmsrs = 1;
282 			break;
283 		case 'c':
284 			cpu = atoi(optarg);
285 			break;
286 		case 'm':
287 			for (s = allsystems; !SYSTEM_ISEOT(*s); s++)
288 				if (!strcmp(s->name, optarg)) {
289 					sys = s;
290 					break;
291 				}
292 			break;
293 		case 't':
294 			for (t = alltargets; !TARGET_ISEOT(*t); t++)
295 				if (!strcmp(t->name, optarg)) {
296 					add_target(t);
297 					break;
298 				}
299 			break;
300 		case 'i':
301 			input = 1;
302 			addr = msraddrbyname(optarg);
303 			optarg = strchr(optarg, '=');
304 			if (NULL == optarg) {
305 				fprintf(stderr, "missing value in -i argument!\n");
306 				break;
307 			}
308 			if (!str2msr(++optarg, &msrval, NULL))
309 				fprintf(stderr, "invalid value in -i argument!\n");
310 			break;
311 		case 's':
312 			streamfn = optarg;
313 			break;
314 		case 'd':
315 			difffn = optarg;
316 			break;
317 		default:
318 			break;
319 		}
320 
321 	/** cpuid is called after reading argv so that verbose is set */
322 	const struct cpuid_t *id = cpuid();
323 
324 	printf_quiet("msrtool %s\n", VERSION);
325 
326 	pacc = pci_alloc();
327 	if (NULL == pacc) {
328 		fprintf(stderr, "Could not initialize PCI library! pci_alloc() failed.\n");
329 		return 1;
330 	}
331 	pci_init(pacc);
332 	pci_scan_bus(pacc);
333 
334 	if (!sys && !input && !listknown)
335 		for (sys = allsystems; !SYSTEM_ISEOT(*sys); sys++) {
336 			printf_verbose("Probing for system %s: %s\n", sys->name, sys->prettyname);
337 			if (!sys->probe(sys))
338 				continue;
339 			printf_quiet("Detected system %s: %s\n", sys->name, sys->prettyname);
340 			break;
341 		}
342 
343 	if (targets)
344 		for (tn = 0; tn < targets_found; tn++)
345 			printf_quiet("Forced target %s: %s\n", targets[tn]->name, targets[tn]->prettyname);
346 	else
347 		for (t = alltargets; !TARGET_ISEOT(*t); t++) {
348 			printf_verbose("Probing for target %s: %s\n", t->name, t->prettyname);
349 			if (!t->probe(t, id))
350 				continue;
351 			printf_quiet("Detected target %s: %s\n", t->name, t->prettyname);
352 			add_target(t);
353 		}
354 
355 	printf_quiet("\n");
356 	fflush(stdout);
357 
358 	if (listknown) {
359 		printf("Known systems:\n");
360 		for (s = allsystems; s->name; s++)
361 			printf("%s: %s\n", s->name, s->prettyname);
362 		printf("\nKnown targets:\n");
363 		for (t = alltargets; t->name; t++) {
364 			if (listmsrs && alltargets != t)
365 				printf("\n");
366 			printf("%s: %s\n", t->name, t->prettyname);
367 			if (listmsrs)
368 				dumpmsrdefs(t);
369 		}
370 		printf("\n");
371 		return 0;
372 	}
373 
374 	if (!targets_found || !targets) {
375 		fprintf(stderr, "Unable to detect a known target; can not decode any MSRs! (Use -t to force)\n");
376 		fprintf(stderr, "Please send a report or patch to [email protected]. Thanks for your help!\n");
377 		fprintf(stderr, "\n");
378 		return 1;
379 	}
380 
381 	if (input) {
382 		decodemsr(cpu, addr, msrval);
383 		return 0;
384 	}
385 
386 	if (listmsrs) {
387 		if (streamfn)
388 			return do_stream(streamfn, 1);
389 		for (tn = 0; tn < targets_found; tn++) {
390 			if (tn)
391 				printf("\n");
392 			dumpmsrdefs(targets[tn]);
393 		}
394 		printf("\n");
395 		return 0;
396 	}
397 
398 	if (streamfn)
399 		return do_stream(streamfn, 0);
400 
401 	if (difffn) {
402 		ret = do_diff(difffn);
403 		goto done;
404 	}
405 
406 	if (optind == argc) {
407 		syntax(argv);
408 		printf("\nNo mode or address(es) specified!\n");
409 		return 1;
410 	}
411 
412 	if (!found_system())
413 		return 1;
414 	if (!sys->open(cpu, SYS_RDONLY))
415 		return 1;
416 
417 	for (; optind < argc; optind++) {
418 		addr = msraddrbyname(argv[optind]);
419 		if (!sys->rdmsr(cpu, addr, &msrval))
420 			break;
421 		decodemsr(cpu, addr, msrval);
422 	}
423 	ret = 0;
424 done:
425 	sys->close(cpu);
426 	return ret;
427 }
428