- added instructions how to update the online documentation
[bochs-mirror.git] / cpu / msr.cc
blob308b394701942a3d64dfb96c09ee15f9a5c44a85
1 /////////////////////////////////////////////////////////////////////////
2 // $Id: msr.cc,v 1.3 2008/12/07 06:15:26 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (c) 2008 Stanislav Shwartsman
6 // Written by Stanislav Shwartsman [sshwarts at sourceforge net]
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
13 // This library 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 GNU
16 // Lesser General Public License for more details.
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 /////////////////////////////////////////////////////////////////////////
24 #define NEED_CPU_REG_SHORTCUTS 1
25 #include "bochs.h"
26 #include "cpu.h"
27 #define LOG_THIS BX_CPU_THIS_PTR
29 #if BX_SUPPORT_X86_64==0
30 // Make life easier for merging code.
31 #define RAX EAX
32 #define RDX EDX
33 #endif
35 void BX_CPP_AttrRegparmN(1) BX_CPU_C::RDMSR(bxInstruction_c *i)
37 #if BX_CPU_LEVEL >= 5
38 if (!real_mode() && CPL!=0) {
39 BX_ERROR(("RDMSR: CPL!=0 not in real mode"));
40 exception(BX_GP_EXCEPTION, 0, 0);
43 /* We have the requested MSR register in ECX */
44 switch(ECX) {
46 #if BX_SUPPORT_SEP
47 case BX_MSR_SYSENTER_CS:
48 RAX = BX_CPU_THIS_PTR msr.sysenter_cs_msr;
49 RDX = 0;
50 break;
52 case BX_MSR_SYSENTER_ESP:
53 RAX = BX_CPU_THIS_PTR msr.sysenter_esp_msr;
54 RDX = 0;
55 break;
57 case BX_MSR_SYSENTER_EIP:
58 RAX = BX_CPU_THIS_PTR msr.sysenter_eip_msr;
59 RDX = 0;
60 break;
61 #endif
63 #if BX_SUPPORT_MTRR
64 case BX_MSR_MTRRCAP: // read only MSR
65 RAX = 0x508;
66 RDX = 0;
67 break;
69 case BX_MSR_MTRRPHYSBASE0:
70 case BX_MSR_MTRRPHYSMASK0:
71 case BX_MSR_MTRRPHYSBASE1:
72 case BX_MSR_MTRRPHYSMASK1:
73 case BX_MSR_MTRRPHYSBASE2:
74 case BX_MSR_MTRRPHYSMASK2:
75 case BX_MSR_MTRRPHYSBASE3:
76 case BX_MSR_MTRRPHYSMASK3:
77 case BX_MSR_MTRRPHYSBASE4:
78 case BX_MSR_MTRRPHYSMASK4:
79 case BX_MSR_MTRRPHYSBASE5:
80 case BX_MSR_MTRRPHYSMASK5:
81 case BX_MSR_MTRRPHYSBASE6:
82 case BX_MSR_MTRRPHYSMASK6:
83 case BX_MSR_MTRRPHYSBASE7:
84 case BX_MSR_MTRRPHYSMASK7:
85 RAX = BX_CPU_THIS_PTR msr.mtrrphys[ECX - BX_MSR_MTRRPHYSBASE0] & 0xffffffff;
86 RDX = BX_CPU_THIS_PTR msr.mtrrphys[ECX - BX_MSR_MTRRPHYSBASE0] >> 32;
87 break;
89 case BX_MSR_MTRRFIX64K_00000:
90 RAX = BX_CPU_THIS_PTR msr.mtrrfix64k_00000 & 0xffffffff;
91 RDX = BX_CPU_THIS_PTR msr.mtrrfix64k_00000 >> 32;
92 break;
93 case BX_MSR_MTRRFIX16K_80000:
94 RAX = BX_CPU_THIS_PTR msr.mtrrfix16k_80000 & 0xffffffff;
95 RDX = BX_CPU_THIS_PTR msr.mtrrfix16k_80000 >> 32;
96 break;
97 case BX_MSR_MTRRFIX16K_A0000:
98 RAX = BX_CPU_THIS_PTR msr.mtrrfix16k_a0000 & 0xffffffff;
99 RDX = BX_CPU_THIS_PTR msr.mtrrfix16k_a0000 >> 32;
100 break;
102 case BX_MSR_MTRRFIX4K_C0000:
103 case BX_MSR_MTRRFIX4K_C8000:
104 case BX_MSR_MTRRFIX4K_D0000:
105 case BX_MSR_MTRRFIX4K_D8000:
106 case BX_MSR_MTRRFIX4K_E0000:
107 case BX_MSR_MTRRFIX4K_E8000:
108 case BX_MSR_MTRRFIX4K_F0000:
109 case BX_MSR_MTRRFIX4K_F8000:
110 RAX = BX_CPU_THIS_PTR msr.mtrrfix4k[ECX - BX_MSR_MTRRFIX4K_C0000] & 0xffffffff;
111 RDX = BX_CPU_THIS_PTR msr.mtrrfix4k[ECX - BX_MSR_MTRRFIX4K_C0000] >> 32;
112 break;
114 case BX_MSR_PAT:
115 RAX = BX_CPU_THIS_PTR msr.pat & 0xffffffff;
116 RDX = BX_CPU_THIS_PTR msr.pat >> 32;
117 break;
119 case BX_MSR_MTRR_DEFTYPE:
120 RAX = BX_CPU_THIS_PTR msr.mtrr_deftype;
121 RDX = 0;
122 break;
123 #endif
125 #if BX_CPU_LEVEL == 5
126 /* The following registers are defined for Pentium only */
127 case BX_MSR_P5_MC_ADDR:
128 case BX_MSR_MC_TYPE:
129 /* TODO */
130 break;
132 case BX_MSR_CESR:
133 /* TODO */
134 break;
135 #else
136 /* These are noops on i686... */
137 case BX_MSR_P5_MC_ADDR:
138 case BX_MSR_MC_TYPE:
139 /* do nothing */
140 break;
142 /* ... And these cause an exception on i686 */
143 case BX_MSR_CESR:
144 case BX_MSR_CTR0:
145 case BX_MSR_CTR1:
146 exception(BX_GP_EXCEPTION, 0, 0);
147 #endif /* BX_CPU_LEVEL == 5 */
149 case BX_MSR_TSC:
150 RDTSC(i);
151 break;
153 /* MSR_APICBASE
154 0:7 Reserved
155 8 This is set if its the BSP
156 9:10 Reserved
157 11 APIC Global Enable bit (1=enabled 0=disabled)
158 12:35 APIC Base Address
159 36:63 Reserved
161 #if BX_SUPPORT_APIC
162 case BX_MSR_APICBASE:
163 RAX = BX_CPU_THIS_PTR msr.apicbase;
164 RDX = 0;
165 BX_INFO(("RDMSR: Read %08x:%08x from MSR_APICBASE", EDX, EAX));
166 break;
167 #endif
169 #if BX_SUPPORT_X86_64
170 case BX_MSR_EFER:
171 RAX = BX_CPU_THIS_PTR efer.get32();
172 RDX = 0;
173 break;
175 case BX_MSR_STAR:
176 RAX = MSR_STAR & 0xffffffff;
177 RDX = MSR_STAR >> 32;
178 break;
180 case BX_MSR_LSTAR:
181 RAX = MSR_LSTAR & 0xffffffff;
182 RDX = MSR_LSTAR >> 32;
183 break;
185 case BX_MSR_CSTAR:
186 RAX = MSR_CSTAR & 0xffffffff;
187 RDX = MSR_CSTAR >> 32;
188 break;
190 case BX_MSR_FMASK:
191 RAX = MSR_FMASK;
192 RDX = 0;
193 break;
195 case BX_MSR_FSBASE:
196 RAX = MSR_FSBASE & 0xffffffff;
197 RDX = MSR_FSBASE >> 32;
198 break;
200 case BX_MSR_GSBASE:
201 RAX = MSR_GSBASE & 0xffffffff;
202 RDX = MSR_GSBASE >> 32;
203 break;
205 case BX_MSR_KERNELGSBASE:
206 RAX = MSR_KERNELGSBASE & 0xffffffff;
207 RDX = MSR_KERNELGSBASE >> 32;
208 break;
210 case BX_MSR_TSC_AUX:
211 RAX = MSR_TSC_AUX; // 32 bit MSR
212 RDX = 0;
213 break;
214 #endif // #if BX_SUPPORT_X86_64
216 default:
217 BX_ERROR(("RDMSR: Unknown register %#x", ECX));
218 #if BX_IGNORE_BAD_MSR
219 RAX = 0;
220 RDX = 0;
221 #else
222 exception(BX_GP_EXCEPTION, 0, 0);
223 #endif
225 #else
226 BX_INFO(("RDMSR: Pentium CPU required, use --enable-cpu-level=5"));
227 exception(BX_UD_EXCEPTION, 0, 0);
228 #endif
231 #if BX_SUPPORT_MTRR
232 BX_CPP_INLINE bx_bool isMemTypeValidMTTR(Bit8u memtype)
234 switch(memtype) {
235 case 0x00: // UC
236 case 0x01: // WC
237 case 0x04: // WT
238 case 0x05: // WP
239 case 0x06: // WB
240 return 1;
241 default:
242 return 0;
246 BX_CPP_INLINE bx_bool isMemTypeValidPAT(Bit8u memtype)
248 return (memtype == 0x07) /* UC- */ || isMemTypeValidMTTR(memtype);
250 #endif
252 void BX_CPP_AttrRegparmN(1) BX_CPU_C::WRMSR(bxInstruction_c *i)
254 #if BX_CPU_LEVEL >= 5
255 if (!real_mode() && CPL!=0) {
256 BX_ERROR(("WRMSR: CPL!=0 not in real mode"));
257 exception(BX_GP_EXCEPTION, 0, 0);
260 Bit64u val64 = ((Bit64u) EDX << 32) | EAX;
262 BX_INSTR_WRMSR(BX_CPU_ID, ECX, val64);
264 /* ECX has the MSR to write to */
265 switch(ECX) {
267 #if BX_SUPPORT_SEP
268 case BX_MSR_SYSENTER_CS:
269 BX_CPU_THIS_PTR msr.sysenter_cs_msr = EAX;
270 break;
272 case BX_MSR_SYSENTER_ESP:
273 #if BX_SUPPORT_X86_64
274 if (! IsCanonical(val64)) {
275 BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_SYSENTER_ESP !"));
276 exception(BX_GP_EXCEPTION, 0, 0);
278 #endif
279 BX_CPU_THIS_PTR msr.sysenter_esp_msr = val64;
280 break;
282 case BX_MSR_SYSENTER_EIP:
283 #if BX_SUPPORT_X86_64
284 if (! IsCanonical(val64)) {
285 BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_SYSENTER_EIP !"));
286 exception(BX_GP_EXCEPTION, 0, 0);
288 #endif
289 BX_CPU_THIS_PTR msr.sysenter_eip_msr = val64;
290 break;
291 #endif
293 #if BX_SUPPORT_MTRR
294 case BX_MSR_MTRRCAP:
295 BX_ERROR(("WRMSR: MTRRCAP is read only MSR"));
296 exception(BX_GP_EXCEPTION, 0, 0);
298 case BX_MSR_MTRRPHYSBASE0:
299 case BX_MSR_MTRRPHYSBASE1:
300 case BX_MSR_MTRRPHYSBASE2:
301 case BX_MSR_MTRRPHYSBASE3:
302 case BX_MSR_MTRRPHYSBASE4:
303 case BX_MSR_MTRRPHYSBASE5:
304 case BX_MSR_MTRRPHYSBASE6:
305 case BX_MSR_MTRRPHYSBASE7:
306 if (! isMemTypeValidMTTR(AL)) {
307 BX_ERROR(("WRMSR: attempt to write invalid Memory Type to BX_MSR_MTRRPHYSBASE"));
308 exception(BX_GP_EXCEPTION, 0, 0);
310 case BX_MSR_MTRRPHYSMASK0:
311 case BX_MSR_MTRRPHYSMASK1:
312 case BX_MSR_MTRRPHYSMASK2:
313 case BX_MSR_MTRRPHYSMASK3:
314 case BX_MSR_MTRRPHYSMASK4:
315 case BX_MSR_MTRRPHYSMASK5:
316 case BX_MSR_MTRRPHYSMASK6:
317 case BX_MSR_MTRRPHYSMASK7:
318 BX_CPU_THIS_PTR msr.mtrrphys[ECX - BX_MSR_MTRRPHYSBASE0] = val64;
319 break;
321 case BX_MSR_MTRRFIX64K_00000:
322 if (! isMemTypeValidMTTR(AL)) {
323 BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_MTRRFIX64K_00000"));
324 exception(BX_GP_EXCEPTION, 0, 0);
326 BX_CPU_THIS_PTR msr.mtrrfix64k_00000 = val64;
327 break;
328 case BX_MSR_MTRRFIX16K_80000:
329 if (! isMemTypeValidMTTR(AL)) {
330 BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_MTRRFIX16K_80000"));
331 exception(BX_GP_EXCEPTION, 0, 0);
333 BX_CPU_THIS_PTR msr.mtrrfix16k_80000 = val64;
334 break;
335 case BX_MSR_MTRRFIX16K_A0000:
336 if (! isMemTypeValidMTTR(AL)) {
337 BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_MTRRFIX16K_A0000"));
338 exception(BX_GP_EXCEPTION, 0, 0);
340 BX_CPU_THIS_PTR msr.mtrrfix16k_a0000 = val64;
341 break;
343 case BX_MSR_MTRRFIX4K_C0000:
344 case BX_MSR_MTRRFIX4K_C8000:
345 case BX_MSR_MTRRFIX4K_D0000:
346 case BX_MSR_MTRRFIX4K_D8000:
347 case BX_MSR_MTRRFIX4K_E0000:
348 case BX_MSR_MTRRFIX4K_E8000:
349 case BX_MSR_MTRRFIX4K_F0000:
350 case BX_MSR_MTRRFIX4K_F8000:
351 BX_CPU_THIS_PTR msr.mtrrfix4k[ECX - BX_MSR_MTRRFIX4K_C0000] = val64;
352 break;
354 case BX_MSR_PAT:
355 if (! isMemTypeValidPAT(AL) || ! isMemTypeValidPAT(AH) ||
356 ! isMemTypeValidPAT((EAX >> 16) & 0xFF) ||
357 ! isMemTypeValidPAT(EAX >> 24) ||
358 ! isMemTypeValidPAT(DL) || ! isMemTypeValidPAT(DH) ||
359 ! isMemTypeValidPAT((EDX >> 16) & 0xFF) ||
360 ! isMemTypeValidPAT(EDX >> 24))
362 BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_PAT"));
363 exception(BX_GP_EXCEPTION, 0, 0);
366 BX_CPU_THIS_PTR msr.pat = val64;
367 break;
369 case BX_MSR_MTRR_DEFTYPE:
370 if (! isMemTypeValidMTTR(AL)) {
371 BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_MTRR_DEFTYPE"));
372 exception(BX_GP_EXCEPTION, 0, 0);
374 BX_CPU_THIS_PTR msr.mtrr_deftype = EAX;
375 break;
376 #endif
378 #if BX_CPU_LEVEL == 5
379 /* The following registers are defined for Pentium only */
380 case BX_MSR_P5_MC_ADDR:
381 case BX_MSR_MC_TYPE:
382 case BX_MSR_CESR:
383 /* TODO */
384 break;
385 #else
386 /* These are noops on i686... */
387 case BX_MSR_P5_MC_ADDR:
388 case BX_MSR_MC_TYPE:
389 /* do nothing */
390 break;
392 /* ... And these cause an exception on i686 */
393 case BX_MSR_CESR:
394 case BX_MSR_CTR0:
395 case BX_MSR_CTR1:
396 exception(BX_GP_EXCEPTION, 0, 0);
397 #endif /* BX_CPU_LEVEL == 5 */
399 case BX_MSR_TSC:
400 BX_CPU_THIS_PTR set_TSC(val64);
401 BX_INFO(("WRMSR: wrote 0x%08x%08x to MSR_TSC", EDX, EAX));
402 break;
404 /* MSR_APICBASE
405 0:7 Reserved
406 8 This is set if its the BSP
407 9:10 Reserved
408 11 APIC Global Enable bit (1=enabled 0=disabled)
409 12:35 APIC Base Address (in Bochs 12:31 because of 32-bit physical addr)
410 36:63 Reserved
412 #if BX_SUPPORT_APIC
413 case BX_MSR_APICBASE:
414 if (BX_CPU_THIS_PTR msr.apicbase & 0x800) {
415 BX_INFO(("WRMSR: wrote %08x:%08x to MSR_APICBASE", EDX, EAX));
416 BX_CPU_THIS_PTR msr.apicbase = EAX; /* ignore the high 32bits */
417 #if BX_PHY_ADDRESS_WIDTH == 32
418 if (EDX != 0) {
419 BX_PANIC(("MSR_APICBASE: Only 32 bit physical address space is emulated !"));
421 #endif
422 BX_CPU_THIS_PTR local_apic.set_base(BX_CPU_THIS_PTR msr.apicbase);
423 // TLB flush is required for emulation correctness
424 TLB_flush(); // don't care about performance of apic relocation
426 else {
427 BX_INFO(("WRMSR: MSR_APICBASE APIC global enable bit cleared !"));
429 break;
430 #endif
432 #if BX_SUPPORT_X86_64
433 case BX_MSR_EFER:
434 if (val64 & ~BX_EFER_SUPPORTED_BITS) {
435 BX_ERROR(("WRMSR: attempt to set reserved bits of EFER MSR !"));
436 exception(BX_GP_EXCEPTION, 0, 0);
439 // #GP(0) if changing EFER.LME when cr0.pg = 1
440 if ((BX_CPU_THIS_PTR efer.get_LME() != ((EAX >> 8) & 1)) &&
441 BX_CPU_THIS_PTR cr0.get_PG())
443 BX_ERROR(("WRMSR: attempt to change LME when CR0.PG=1"));
444 exception(BX_GP_EXCEPTION, 0, 0);
447 BX_CPU_THIS_PTR efer.set32((EAX & BX_EFER_SUPPORTED_BITS & ~BX_EFER_LMA_MASK)
448 | (BX_CPU_THIS_PTR efer.val32 & BX_EFER_LMA_MASK)); // keep LMA untouched
449 break;
451 case BX_MSR_STAR:
452 MSR_STAR = val64;
453 break;
455 case BX_MSR_LSTAR:
456 if (! IsCanonical(val64)) {
457 BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_LSTAR !"));
458 exception(BX_GP_EXCEPTION, 0, 0);
460 MSR_LSTAR = val64;
461 break;
463 case BX_MSR_CSTAR:
464 if (! IsCanonical(val64)) {
465 BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_CSTAR !"));
466 exception(BX_GP_EXCEPTION, 0, 0);
468 MSR_CSTAR = val64;
469 break;
471 case BX_MSR_FMASK:
472 MSR_FMASK = (Bit32u) val64;
473 break;
475 case BX_MSR_FSBASE:
476 if (! IsCanonical(val64)) {
477 BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_FSBASE !"));
478 exception(BX_GP_EXCEPTION, 0, 0);
480 MSR_FSBASE = val64;
481 break;
483 case BX_MSR_GSBASE:
484 if (! IsCanonical(val64)) {
485 BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_GSBASE !"));
486 exception(BX_GP_EXCEPTION, 0, 0);
488 MSR_GSBASE = val64;
489 break;
491 case BX_MSR_KERNELGSBASE:
492 if (! IsCanonical(val64)) {
493 BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_KERNELGSBASE !"));
494 exception(BX_GP_EXCEPTION, 0, 0);
496 MSR_KERNELGSBASE = val64;
497 break;
499 case BX_MSR_TSC_AUX:
500 MSR_TSC_AUX = EAX;
501 break;
502 #endif // #if BX_SUPPORT_X86_64
504 default:
505 BX_ERROR(("WRMSR: Unknown register %#x", ECX));
506 #if BX_IGNORE_BAD_MSR == 0
507 exception(BX_GP_EXCEPTION, 0, 0);
508 #endif
510 #else
511 BX_INFO(("WRMSR: Pentium CPU required, use --enable-cpu-level=5"));
512 exception(BX_UD_EXCEPTION, 0, 0);
513 #endif