blob: 98e51d44115cf8fd7dac0fe5cd2870b20699fcf2 [file] [log] [blame]
Thomas Heijligenb3287b42021-12-14 17:25:49 +01001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2009 Peter Stuge <peter@stuge.se>
5 * Copyright (C) 2009 coresystems GmbH
6 * Copyright (C) 2010 Carl-Daniel Hailfinger
7 * Copyright (C) 2010 Rudolf Marek <r.marek@assembler.cz>
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
Thomas Heijligen5618d5b2022-02-19 21:17:44 +010020 * and a non-working default implementation on the bottom.
Thomas Heijligenb3287b42021-12-14 17:25:49 +010021 */
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
42static int fd_msr = -1;
43
Thomas Heijligenf8d9a272022-03-16 09:19:19 +010044msr_t msr_read(int addr)
Thomas Heijligenb3287b42021-12-14 17:25:49 +010045{
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
Thomas Heijligenf8d9a272022-03-16 09:19:19 +010071int msr_write(int addr, msr_t msr)
Thomas Heijligenb3287b42021-12-14 17:25:49 +010072{
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
Thomas Heijligenf8d9a272022-03-16 09:19:19 +010096int msr_setup(int cpu)
Thomas Heijligenb3287b42021-12-14 17:25:49 +010097{
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
Thomas Heijligenf8d9a272022-03-16 09:19:19 +0100117void msr_cleanup(void)
Thomas Heijligenb3287b42021-12-14 17:25:49 +0100118{
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). */
Thomas Heijligenf8d9a272022-03-16 09:19:19 +0100130#include <stdlib.h>
Thomas Heijligenb3287b42021-12-14 17:25:49 +0100131#include <stdint.h>
132#include <stdio.h>
Thomas Heijligenf8d9a272022-03-16 09:19:19 +0100133#include <string.h>
134#include <errno.h>
135#include <fcntl.h>
136#include <unistd.h>
Thomas Heijligenb3287b42021-12-14 17:25:49 +0100137#include <sys/ioctl.h>
138#include <machine/amdmsr.h>
139
140static int fd_msr = -1;
141
Thomas Heijligenf8d9a272022-03-16 09:19:19 +0100142msr_t msr_read(int addr)
Thomas Heijligenb3287b42021-12-14 17:25:49 +0100143{
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
Thomas Heijligenf8d9a272022-03-16 09:19:19 +0100162int msr_write(int addr, msr_t msr)
Thomas Heijligenb3287b42021-12-14 17:25:49 +0100163{
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
Thomas Heijligenf8d9a272022-03-16 09:19:19 +0100178int msr_setup(int cpu)
Thomas Heijligenb3287b42021-12-14 17:25:49 +0100179{
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
Thomas Heijligenf8d9a272022-03-16 09:19:19 +0100198void msr_cleanup(void)
Thomas Heijligenb3287b42021-12-14 17:25:49 +0100199{
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
221typedef 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
228static int fd_msr = -1;
229
Thomas Heijligenf8d9a272022-03-16 09:19:19 +0100230msr_t msr_read(int addr)
Thomas Heijligenb3287b42021-12-14 17:25:49 +0100231{
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
Thomas Heijligenf8d9a272022-03-16 09:19:19 +0100250int msr_write(int addr, msr_t msr)
Thomas Heijligenb3287b42021-12-14 17:25:49 +0100251{
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
Thomas Heijligenf8d9a272022-03-16 09:19:19 +0100266int msr_setup(int cpu)
Thomas Heijligenb3287b42021-12-14 17:25:49 +0100267{
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
Thomas Heijligenf8d9a272022-03-16 09:19:19 +0100287void msr_cleanup(void)
Thomas Heijligenb3287b42021-12-14 17:25:49 +0100288{
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__)
Thomas Heijligenf8d9a272022-03-16 09:19:19 +0100301/*
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
310msr_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
317int msr_write(int addr, msr_t msr)
318{
319 return wrmsr(addr, (directhw_msr_t){msr.hi, msr.lo});
320}
321
322int msr_setup(int cpu)
Thomas Heijligenb3287b42021-12-14 17:25:49 +0100323{
324 // Always succeed for now
325 return 0;
326}
327
Thomas Heijligenf8d9a272022-03-16 09:19:19 +0100328void msr_cleanup(void)
Thomas Heijligenb3287b42021-12-14 17:25:49 +0100329{
330 // Nothing, yet.
331}
332#elif defined(__LIBPAYLOAD__)
Thomas Heijligenf8d9a272022-03-16 09:19:19 +0100333#include <arch/msr.h>
334
335msr_t msr_read(int addr)
Thomas Heijligenb3287b42021-12-14 17:25:49 +0100336{
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
Thomas Heijligenf8d9a272022-03-16 09:19:19 +0100344int msr_write(int addr, msr_t msr)
Thomas Heijligenb3287b42021-12-14 17:25:49 +0100345{
346 _wrmsr(addr, msr.lo | ((unsigned long long)msr.hi << 32));
347 return 0;
348}
349
Thomas Heijligenf8d9a272022-03-16 09:19:19 +0100350int msr_setup(int cpu)
Thomas Heijligenb3287b42021-12-14 17:25:49 +0100351{
352 return 0;
353}
354
Thomas Heijligenf8d9a272022-03-16 09:19:19 +0100355void msr_cleanup(void)
Thomas Heijligenb3287b42021-12-14 17:25:49 +0100356{
357}
358#else
359/* default MSR implementation */
Thomas Heijligenf8d9a272022-03-16 09:19:19 +0100360msr_t msr_read(int addr)
Thomas Heijligenb3287b42021-12-14 17:25:49 +0100361{
362 msr_t ret = { 0xffffffff, 0xffffffff };
363
364 return ret;
365}
366
Thomas Heijligenf8d9a272022-03-16 09:19:19 +0100367int msr_write(int addr, msr_t msr)
Thomas Heijligenb3287b42021-12-14 17:25:49 +0100368{
369 return -1;
370}
371
Thomas Heijligenf8d9a272022-03-16 09:19:19 +0100372int msr_setup(int cpu)
Thomas Heijligenb3287b42021-12-14 17:25:49 +0100373{
374 msg_pinfo("No MSR support for your OS yet.\n");
375 return -1;
376}
377
Thomas Heijligenf8d9a272022-03-16 09:19:19 +0100378void msr_cleanup(void)
Thomas Heijligenb3287b42021-12-14 17:25:49 +0100379{
380 // Nothing, yet.
381}
382#endif // OS switches for MSR code