1 /////////////////////////////////////////////////////////////////////////
2 // $Id: msr.cc,v 1.3 2008/12/07 06:15:26 sshwarts Exp $
3 /////////////////////////////////////////////////////////////////////////
5 // Copyright (c) 2008 Stanislav Shwartsman
6 // Written by Stanislav Shwartsman [sshwarts at sourceforge net]
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
27 #define LOG_THIS BX_CPU_THIS_PTR
29 #if BX_SUPPORT_X86_64==0
30 // Make life easier for merging code.
35 void BX_CPP_AttrRegparmN(1) BX_CPU_C::RDMSR(bxInstruction_c
*i
)
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 */
47 case BX_MSR_SYSENTER_CS
:
48 RAX
= BX_CPU_THIS_PTR msr
.sysenter_cs_msr
;
52 case BX_MSR_SYSENTER_ESP
:
53 RAX
= BX_CPU_THIS_PTR msr
.sysenter_esp_msr
;
57 case BX_MSR_SYSENTER_EIP
:
58 RAX
= BX_CPU_THIS_PTR msr
.sysenter_eip_msr
;
64 case BX_MSR_MTRRCAP
: // read only MSR
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;
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;
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;
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;
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;
115 RAX
= BX_CPU_THIS_PTR msr
.pat
& 0xffffffff;
116 RDX
= BX_CPU_THIS_PTR msr
.pat
>> 32;
119 case BX_MSR_MTRR_DEFTYPE
:
120 RAX
= BX_CPU_THIS_PTR msr
.mtrr_deftype
;
125 #if BX_CPU_LEVEL == 5
126 /* The following registers are defined for Pentium only */
127 case BX_MSR_P5_MC_ADDR
:
136 /* These are noops on i686... */
137 case BX_MSR_P5_MC_ADDR
:
142 /* ... And these cause an exception on i686 */
146 exception(BX_GP_EXCEPTION
, 0, 0);
147 #endif /* BX_CPU_LEVEL == 5 */
155 8 This is set if its the BSP
157 11 APIC Global Enable bit (1=enabled 0=disabled)
158 12:35 APIC Base Address
162 case BX_MSR_APICBASE
:
163 RAX
= BX_CPU_THIS_PTR msr
.apicbase
;
165 BX_INFO(("RDMSR: Read %08x:%08x from MSR_APICBASE", EDX
, EAX
));
169 #if BX_SUPPORT_X86_64
171 RAX
= BX_CPU_THIS_PTR efer
.get32();
176 RAX
= MSR_STAR
& 0xffffffff;
177 RDX
= MSR_STAR
>> 32;
181 RAX
= MSR_LSTAR
& 0xffffffff;
182 RDX
= MSR_LSTAR
>> 32;
186 RAX
= MSR_CSTAR
& 0xffffffff;
187 RDX
= MSR_CSTAR
>> 32;
196 RAX
= MSR_FSBASE
& 0xffffffff;
197 RDX
= MSR_FSBASE
>> 32;
201 RAX
= MSR_GSBASE
& 0xffffffff;
202 RDX
= MSR_GSBASE
>> 32;
205 case BX_MSR_KERNELGSBASE
:
206 RAX
= MSR_KERNELGSBASE
& 0xffffffff;
207 RDX
= MSR_KERNELGSBASE
>> 32;
211 RAX
= MSR_TSC_AUX
; // 32 bit MSR
214 #endif // #if BX_SUPPORT_X86_64
217 BX_ERROR(("RDMSR: Unknown register %#x", ECX
));
218 #if BX_IGNORE_BAD_MSR
222 exception(BX_GP_EXCEPTION
, 0, 0);
226 BX_INFO(("RDMSR: Pentium CPU required, use --enable-cpu-level=5"));
227 exception(BX_UD_EXCEPTION
, 0, 0);
232 BX_CPP_INLINE bx_bool
isMemTypeValidMTTR(Bit8u memtype
)
246 BX_CPP_INLINE bx_bool
isMemTypeValidPAT(Bit8u memtype
)
248 return (memtype
== 0x07) /* UC- */ || isMemTypeValidMTTR(memtype
);
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 */
268 case BX_MSR_SYSENTER_CS
:
269 BX_CPU_THIS_PTR msr
.sysenter_cs_msr
= EAX
;
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);
279 BX_CPU_THIS_PTR msr
.sysenter_esp_msr
= val64
;
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);
289 BX_CPU_THIS_PTR msr
.sysenter_eip_msr
= val64
;
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
;
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
;
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
;
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
;
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
;
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
;
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
;
378 #if BX_CPU_LEVEL == 5
379 /* The following registers are defined for Pentium only */
380 case BX_MSR_P5_MC_ADDR
:
386 /* These are noops on i686... */
387 case BX_MSR_P5_MC_ADDR
:
392 /* ... And these cause an exception on i686 */
396 exception(BX_GP_EXCEPTION
, 0, 0);
397 #endif /* BX_CPU_LEVEL == 5 */
400 BX_CPU_THIS_PTR
set_TSC(val64
);
401 BX_INFO(("WRMSR: wrote 0x%08x%08x to MSR_TSC", EDX
, EAX
));
406 8 This is set if its the BSP
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)
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
419 BX_PANIC(("MSR_APICBASE: Only 32 bit physical address space is emulated !"));
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
427 BX_INFO(("WRMSR: MSR_APICBASE APIC global enable bit cleared !"));
432 #if BX_SUPPORT_X86_64
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
456 if (! IsCanonical(val64
)) {
457 BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_LSTAR !"));
458 exception(BX_GP_EXCEPTION
, 0, 0);
464 if (! IsCanonical(val64
)) {
465 BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_CSTAR !"));
466 exception(BX_GP_EXCEPTION
, 0, 0);
472 MSR_FMASK
= (Bit32u
) val64
;
476 if (! IsCanonical(val64
)) {
477 BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_FSBASE !"));
478 exception(BX_GP_EXCEPTION
, 0, 0);
484 if (! IsCanonical(val64
)) {
485 BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_GSBASE !"));
486 exception(BX_GP_EXCEPTION
, 0, 0);
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
;
502 #endif // #if BX_SUPPORT_X86_64
505 BX_ERROR(("WRMSR: Unknown register %#x", ECX
));
506 #if BX_IGNORE_BAD_MSR == 0
507 exception(BX_GP_EXCEPTION
, 0, 0);
511 BX_INFO(("WRMSR: Pentium CPU required, use --enable-cpu-level=5"));
512 exception(BX_UD_EXCEPTION
, 0, 0);