blob: 3728061178af7c3f244f127f722a9eeb73bf21d5 [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
44msr_t rdmsr(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
71int wrmsr(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
96int setup_cpu_msr(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
117void cleanup_cpu_msr(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 <stdint.h>
131#include <stdio.h>
132#include <sys/ioctl.h>
133#include <machine/amdmsr.h>
134
135static int fd_msr = -1;
136
137msr_t rdmsr(int addr)
138{
139 struct amdmsr_req args;
140
141 msr_t msr = { 0xffffffff, 0xffffffff };
142
143 args.addr = (uint32_t)addr;
144
145 if (ioctl(fd_msr, RDMSR, &args) < 0) {
146 msg_perr("Error while executing RDMSR ioctl: %s\n", strerror(errno));
147 close(fd_msr);
148 exit(1);
149 }
150
151 msr.lo = args.val & 0xffffffff;
152 msr.hi = args.val >> 32;
153
154 return msr;
155}
156
157int wrmsr(int addr, msr_t msr)
158{
159 struct amdmsr_req args;
160
161 args.addr = addr;
162 args.val = (((uint64_t)msr.hi) << 32) | msr.lo;
163
164 if (ioctl(fd_msr, WRMSR, &args) < 0) {
165 msg_perr("Error while executing WRMSR ioctl: %s\n", strerror(errno));
166 close(fd_msr);
167 exit(1);
168 }
169
170 return 0;
171}
172
173int setup_cpu_msr(int cpu)
174{
175 char msrfilename[64] = { 0 };
176 snprintf(msrfilename, sizeof(msrfilename), "/dev/amdmsr");
177
178 if (fd_msr != -1) {
179 msg_pinfo("MSR was already initialized\n");
180 return -1;
181 }
182
183 fd_msr = open(msrfilename, O_RDWR);
184
185 if (fd_msr < 0) {
186 msg_perr("Error while opening %s: %s\n", msrfilename, strerror(errno));
187 return -1;
188 }
189
190 return 0;
191}
192
193void cleanup_cpu_msr(void)
194{
195 if (fd_msr == -1) {
196 msg_pinfo("No MSR initialized.\n");
197 return;
198 }
199
200 close(fd_msr);
201
202 /* Clear MSR file descriptor. */
203 fd_msr = -1;
204}
205
206#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
207#include <stdint.h>
208#include <stdlib.h>
209#include <errno.h>
210#include <fcntl.h>
211#include <string.h>
212#include <unistd.h>
213
214#include <sys/ioctl.h>
215
216typedef struct {
217 int msr;
218 uint64_t data;
219} cpu_msr_args_t;
220#define CPU_RDMSR _IOWR('c', 1, cpu_msr_args_t)
221#define CPU_WRMSR _IOWR('c', 2, cpu_msr_args_t)
222
223static int fd_msr = -1;
224
225msr_t rdmsr(int addr)
226{
227 cpu_msr_args_t args;
228
229 msr_t msr = { 0xffffffff, 0xffffffff };
230
231 args.msr = addr;
232
233 if (ioctl(fd_msr, CPU_RDMSR, &args) < 0) {
234 msg_perr("Error while executing CPU_RDMSR ioctl: %s\n", strerror(errno));
235 close(fd_msr);
236 exit(1);
237 }
238
239 msr.lo = args.data & 0xffffffff;
240 msr.hi = args.data >> 32;
241
242 return msr;
243}
244
245int wrmsr(int addr, msr_t msr)
246{
247 cpu_msr_args_t args;
248
249 args.msr = addr;
250 args.data = (((uint64_t)msr.hi) << 32) | msr.lo;
251
252 if (ioctl(fd_msr, CPU_WRMSR, &args) < 0) {
253 msg_perr("Error while executing CPU_WRMSR ioctl: %s\n", strerror(errno));
254 close(fd_msr);
255 exit(1);
256 }
257
258 return 0;
259}
260
261int setup_cpu_msr(int cpu)
262{
263 char msrfilename[64] = { 0 };
264 snprintf(msrfilename, sizeof(msrfilename), "/dev/cpu%d", cpu);
265
266 if (fd_msr != -1) {
267 msg_pinfo("MSR was already initialized\n");
268 return -1;
269 }
270
271 fd_msr = open(msrfilename, O_RDWR);
272
273 if (fd_msr < 0) {
274 msg_perr("Error while opening %s: %s\n", msrfilename, strerror(errno));
275 msg_pinfo("Did you install ports/sysutils/devcpu?\n");
276 return -1;
277 }
278
279 return 0;
280}
281
282void cleanup_cpu_msr(void)
283{
284 if (fd_msr == -1) {
285 msg_pinfo("No MSR initialized.\n");
286 return;
287 }
288
289 close(fd_msr);
290
291 /* Clear MSR file descriptor. */
292 fd_msr = -1;
293}
294
295#elif defined(__MACH__) && defined(__APPLE__)
296/* rdmsr() and wrmsr() are provided by DirectHW which needs neither setup nor cleanup. */
297int setup_cpu_msr(int cpu)
298{
299 // Always succeed for now
300 return 0;
301}
302
303void cleanup_cpu_msr(void)
304{
305 // Nothing, yet.
306}
307#elif defined(__LIBPAYLOAD__)
308msr_t libpayload_rdmsr(int addr)
309{
310 msr_t msr;
311 unsigned long long val = _rdmsr(addr);
312 msr.lo = val & 0xffffffff;
313 msr.hi = val >> 32;
314 return msr;
315}
316
317int libpayload_wrmsr(int addr, msr_t msr)
318{
319 _wrmsr(addr, msr.lo | ((unsigned long long)msr.hi << 32));
320 return 0;
321}
322
323int setup_cpu_msr(int cpu)
324{
325 return 0;
326}
327
328void cleanup_cpu_msr(void)
329{
330}
331#else
332/* default MSR implementation */
333msr_t rdmsr(int addr)
334{
335 msr_t ret = { 0xffffffff, 0xffffffff };
336
337 return ret;
338}
339
340int wrmsr(int addr, msr_t msr)
341{
342 return -1;
343}
344
345int setup_cpu_msr(int cpu)
346{
347 msg_pinfo("No MSR support for your OS yet.\n");
348 return -1;
349}
350
351void cleanup_cpu_msr(void)
352{
353 // Nothing, yet.
354}
355#endif // OS switches for MSR code