xref: /aosp_15_r20/external/flashrom/hwaccess_x86_msr.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
1 /*
2  * This file is part of the flashrom project.
3  *
4  * Copyright (C) 2009 Peter Stuge <[email protected]>
5  * Copyright (C) 2009 coresystems GmbH
6  * Copyright (C) 2010 Carl-Daniel Hailfinger
7  * Copyright (C) 2010 Rudolf Marek <[email protected]>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; version 2 of the License.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  */
18 
19 /* MSR abstraction implementations for Linux, OpenBSD, FreeBSD/Dragonfly, OSX, libpayload
20  * and a non-working default implementation on the bottom.
21  */
22 
23 #include "hwaccess_x86_msr.h"
24 #include "flash.h"
25 
26 #ifdef __linux__
27 /*
28  * Reading and writing to MSRs, however requires instructions rdmsr/wrmsr,
29  * which are ring0 privileged instructions so only the kernel can do the
30  * read/write. This function, therefore, requires that the msr kernel module
31  * be loaded to access these instructions from user space using device
32  * /dev/cpu/0/msr.
33  */
34 
35 #include <stdint.h>
36 #include <stdlib.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <string.h>
40 #include <unistd.h>
41 
42 static int fd_msr = -1;
43 
msr_read(int addr)44 msr_t msr_read(int addr)
45 {
46 	uint32_t buf[2];
47 	msr_t msr = { 0xffffffff, 0xffffffff };
48 
49 	if (lseek(fd_msr, (off_t) addr, SEEK_SET) == -1) {
50 		msg_perr("Could not lseek() MSR: %s\n", strerror(errno));
51 		close(fd_msr);
52 		exit(1);
53 	}
54 
55 	if (read(fd_msr, buf, 8) == 8) {
56 		msr.lo = buf[0];
57 		msr.hi = buf[1];
58 		return msr;
59 	}
60 
61 	if (errno != EIO) {
62 		// A severe error.
63 		msg_perr("Could not read() MSR: %s\n", strerror(errno));
64 		close(fd_msr);
65 		exit(1);
66 	}
67 
68 	return msr;
69 }
70 
msr_write(int addr,msr_t msr)71 int msr_write(int addr, msr_t msr)
72 {
73 	uint32_t buf[2];
74 	buf[0] = msr.lo;
75 	buf[1] = msr.hi;
76 
77 	if (lseek(fd_msr, (off_t) addr, SEEK_SET) == -1) {
78 		msg_perr("Could not lseek() MSR: %s\n", strerror(errno));
79 		close(fd_msr);
80 		exit(1);
81 	}
82 
83 	if (write(fd_msr, buf, 8) != 8 && errno != EIO) {
84 		msg_perr("Could not write() MSR: %s\n", strerror(errno));
85 		close(fd_msr);
86 		exit(1);
87 	}
88 
89 	/* Some MSRs must not be written. */
90 	if (errno == EIO)
91 		return -1;
92 
93 	return 0;
94 }
95 
msr_setup(int cpu)96 int msr_setup(int cpu)
97 {
98 	char msrfilename[64] = { 0 };
99 	snprintf(msrfilename, sizeof(msrfilename), "/dev/cpu/%d/msr", cpu);
100 
101 	if (fd_msr != -1) {
102 		msg_pinfo("MSR was already initialized\n");
103 		return -1;
104 	}
105 
106 	fd_msr = open(msrfilename, O_RDWR);
107 
108 	if (fd_msr < 0) {
109 		msg_perr("Error while opening %s: %s\n", msrfilename, strerror(errno));
110 		msg_pinfo("Did you run 'modprobe msr'?\n");
111 		return -1;
112 	}
113 
114 	return 0;
115 }
116 
msr_cleanup(void)117 void msr_cleanup(void)
118 {
119 	if (fd_msr == -1) {
120 		msg_pinfo("No MSR initialized.\n");
121 		return;
122 	}
123 
124 	close(fd_msr);
125 
126 	/* Clear MSR file descriptor. */
127 	fd_msr = -1;
128 }
129 #elif defined(__OpenBSD__) && defined (__i386__) /* This does only work for certain AMD Geode LX systems see amdmsr(4). */
130 #include <stdlib.h>
131 #include <stdint.h>
132 #include <stdio.h>
133 #include <string.h>
134 #include <errno.h>
135 #include <fcntl.h>
136 #include <unistd.h>
137 #include <sys/ioctl.h>
138 #include <machine/amdmsr.h>
139 
140 static int fd_msr = -1;
141 
msr_read(int addr)142 msr_t msr_read(int addr)
143 {
144 	struct amdmsr_req args;
145 
146 	msr_t msr = { 0xffffffff, 0xffffffff };
147 
148 	args.addr = (uint32_t)addr;
149 
150 	if (ioctl(fd_msr, RDMSR, &args) < 0) {
151 		msg_perr("Error while executing RDMSR ioctl: %s\n", strerror(errno));
152 		close(fd_msr);
153 		exit(1);
154 	}
155 
156 	msr.lo = args.val & 0xffffffff;
157 	msr.hi = args.val >> 32;
158 
159 	return msr;
160 }
161 
msr_write(int addr,msr_t msr)162 int msr_write(int addr, msr_t msr)
163 {
164 	struct amdmsr_req args;
165 
166 	args.addr = addr;
167 	args.val = (((uint64_t)msr.hi) << 32) | msr.lo;
168 
169 	if (ioctl(fd_msr, WRMSR, &args) < 0) {
170 		msg_perr("Error while executing WRMSR ioctl: %s\n", strerror(errno));
171 		close(fd_msr);
172 		exit(1);
173 	}
174 
175 	return 0;
176 }
177 
msr_setup(int cpu)178 int msr_setup(int cpu)
179 {
180 	char msrfilename[64] = { 0 };
181 	snprintf(msrfilename, sizeof(msrfilename), "/dev/amdmsr");
182 
183 	if (fd_msr != -1) {
184 		msg_pinfo("MSR was already initialized\n");
185 		return -1;
186 	}
187 
188 	fd_msr = open(msrfilename, O_RDWR);
189 
190 	if (fd_msr < 0) {
191 		msg_perr("Error while opening %s: %s\n", msrfilename, strerror(errno));
192 		return -1;
193 	}
194 
195 	return 0;
196 }
197 
msr_cleanup(void)198 void msr_cleanup(void)
199 {
200 	if (fd_msr == -1) {
201 		msg_pinfo("No MSR initialized.\n");
202 		return;
203 	}
204 
205 	close(fd_msr);
206 
207 	/* Clear MSR file descriptor. */
208 	fd_msr = -1;
209 }
210 
211 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
212 #include <stdint.h>
213 #include <stdlib.h>
214 #include <errno.h>
215 #include <fcntl.h>
216 #include <string.h>
217 #include <unistd.h>
218 
219 #include <sys/ioctl.h>
220 
221 typedef struct {
222 	int msr;
223 	uint64_t data;
224 } cpu_msr_args_t;
225 #define CPU_RDMSR _IOWR('c', 1, cpu_msr_args_t)
226 #define CPU_WRMSR _IOWR('c', 2, cpu_msr_args_t)
227 
228 static int fd_msr = -1;
229 
msr_read(int addr)230 msr_t msr_read(int addr)
231 {
232 	cpu_msr_args_t args;
233 
234 	msr_t msr = { 0xffffffff, 0xffffffff };
235 
236 	args.msr = addr;
237 
238 	if (ioctl(fd_msr, CPU_RDMSR, &args) < 0) {
239 		msg_perr("Error while executing CPU_RDMSR ioctl: %s\n", strerror(errno));
240 		close(fd_msr);
241 		exit(1);
242 	}
243 
244 	msr.lo = args.data & 0xffffffff;
245 	msr.hi = args.data >> 32;
246 
247 	return msr;
248 }
249 
msr_write(int addr,msr_t msr)250 int msr_write(int addr, msr_t msr)
251 {
252 	cpu_msr_args_t args;
253 
254 	args.msr = addr;
255 	args.data = (((uint64_t)msr.hi) << 32) | msr.lo;
256 
257 	if (ioctl(fd_msr, CPU_WRMSR, &args) < 0) {
258 		msg_perr("Error while executing CPU_WRMSR ioctl: %s\n", strerror(errno));
259 		close(fd_msr);
260 		exit(1);
261 	}
262 
263 	return 0;
264 }
265 
msr_setup(int cpu)266 int msr_setup(int cpu)
267 {
268 	char msrfilename[64] = { 0 };
269 	snprintf(msrfilename, sizeof(msrfilename), "/dev/cpu%d", cpu);
270 
271 	if (fd_msr != -1) {
272 		msg_pinfo("MSR was already initialized\n");
273 		return -1;
274 	}
275 
276 	fd_msr = open(msrfilename, O_RDWR);
277 
278 	if (fd_msr < 0) {
279 		msg_perr("Error while opening %s: %s\n", msrfilename, strerror(errno));
280 		msg_pinfo("Did you install ports/sysutils/devcpu?\n");
281 		return -1;
282 	}
283 
284 	return 0;
285 }
286 
msr_cleanup(void)287 void msr_cleanup(void)
288 {
289 	if (fd_msr == -1) {
290 		msg_pinfo("No MSR initialized.\n");
291 		return;
292 	}
293 
294 	close(fd_msr);
295 
296 	/* Clear MSR file descriptor. */
297 	fd_msr = -1;
298 }
299 
300 #elif defined(__MACH__) && defined(__APPLE__)
301 /*
302  * DirectHW has identical, but conflicting typedef for msr_t. We redefine msr_t
303  * to directhw_msr_t for DirectHW.
304  * rdmsr() and wrmsr() are provided by DirectHW and need neither setup nor cleanup.
305  */
306 #define msr_t directhw_msr_t
307 #include <DirectHW/DirectHW.h>
308 #undef msr_t
309 
msr_read(int addr)310 msr_t msr_read(int addr)
311 {
312 	directhw_msr_t msr;
313 	msr = rdmsr(addr);
314 	return (msr_t){msr.hi, msr.lo};
315 }
316 
msr_write(int addr,msr_t msr)317 int msr_write(int addr, msr_t msr)
318 {
319 	return wrmsr(addr, (directhw_msr_t){msr.hi, msr.lo});
320 }
321 
msr_setup(int cpu)322 int msr_setup(int cpu)
323 {
324 	// Always succeed for now
325 	return 0;
326 }
327 
msr_cleanup(void)328 void msr_cleanup(void)
329 {
330 	// Nothing, yet.
331 }
332 #elif defined(__LIBPAYLOAD__)
333 #include <arch/msr.h>
334 
msr_read(int addr)335 msr_t msr_read(int addr)
336 {
337 	msr_t msr;
338 	unsigned long long val = _rdmsr(addr);
339 	msr.lo = val & 0xffffffff;
340 	msr.hi = val >> 32;
341 	return msr;
342 }
343 
msr_write(int addr,msr_t msr)344 int msr_write(int addr, msr_t msr)
345 {
346 	_wrmsr(addr, msr.lo | ((unsigned long long)msr.hi << 32));
347 	return 0;
348 }
349 
msr_setup(int cpu)350 int msr_setup(int cpu)
351 {
352 	return 0;
353 }
354 
msr_cleanup(void)355 void msr_cleanup(void)
356 {
357 }
358 #else
359 /* default MSR implementation */
msr_read(int addr)360 msr_t msr_read(int addr)
361 {
362 	msr_t ret = { 0xffffffff, 0xffffffff };
363 
364 	return ret;
365 }
366 
msr_write(int addr,msr_t msr)367 int msr_write(int addr, msr_t msr)
368 {
369 	return -1;
370 }
371 
msr_setup(int cpu)372 int msr_setup(int cpu)
373 {
374 	msg_pinfo("No MSR support for your OS yet.\n");
375 	return -1;
376 }
377 
msr_cleanup(void)378 void msr_cleanup(void)
379 {
380 	// Nothing, yet.
381 }
382 #endif // OS switches for MSR code
383