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