Implement missing Pentium MSRs
Includes obscure behavior, like undocumented "high" MSRs
This commit is contained in:
299
src/cpu/cpu.c
299
src/cpu/cpu.c
@@ -248,8 +248,7 @@ uint32_t cache_index = 0;
|
|||||||
uint8_t _cache[2048];
|
uint8_t _cache[2048];
|
||||||
|
|
||||||
uint64_t cpu_CR4_mask;
|
uint64_t cpu_CR4_mask;
|
||||||
uint64_t tsc = 0;
|
uint64_t tsc = 0;
|
||||||
uint64_t pmc[2] = { 0, 0 };
|
|
||||||
|
|
||||||
double cpu_dmulti;
|
double cpu_dmulti;
|
||||||
double cpu_busspeed;
|
double cpu_busspeed;
|
||||||
@@ -2824,17 +2823,159 @@ amd_k_invalid_rdmsr:
|
|||||||
case CPU_PENTIUM:
|
case CPU_PENTIUM:
|
||||||
case CPU_PENTIUMMMX:
|
case CPU_PENTIUMMMX:
|
||||||
EAX = EDX = 0;
|
EAX = EDX = 0;
|
||||||
switch (ECX) {
|
/* Filter out the upper 27 bits when ECX value is over 0x80000000, as per:
|
||||||
|
Ralf Brown, Pentium Model-Specific Registers and What They Reveal.
|
||||||
|
https://www.cs.cmu.edu/~ralf/papers/highmsr.html
|
||||||
|
But leave the bit 31 intact to be able to handle both low and high
|
||||||
|
MSRs in a single switch block. */
|
||||||
|
switch (ECX & (ECX > 0x7fffffff ? 0x8000001f : 0x7fffffff)) {
|
||||||
/* Machine Check Exception Address */
|
/* Machine Check Exception Address */
|
||||||
case 0x00:
|
case 0x00000000:
|
||||||
|
case 0x80000000:
|
||||||
|
EAX = msr.mcar & 0xffffffff;
|
||||||
|
EDX = msr.mcar >> 32;
|
||||||
|
break;
|
||||||
/* Machine Check Exception Type */
|
/* Machine Check Exception Type */
|
||||||
case 0x01:
|
case 0x00000001:
|
||||||
|
case 0x80000001:
|
||||||
|
EAX = msr.mctr & 0xffffffff;
|
||||||
|
EDX = msr.mctr >> 32;
|
||||||
|
msr.mctr &= ~0x1; /* clear the machine check pending bit */
|
||||||
|
break;
|
||||||
|
/* TR1 - Parity Reversal Test Register */
|
||||||
|
case 0x00000002:
|
||||||
|
case 0x80000002:
|
||||||
|
EAX = msr.tr1;
|
||||||
|
break;
|
||||||
|
/* TR2 - Instruction Cache End Bit */
|
||||||
|
case 0x00000004:
|
||||||
|
case 0x80000004:
|
||||||
|
if (cpu_s->cpu_type == CPU_PENTIUMMMX)
|
||||||
|
goto pentium_invalid_rdmsr;
|
||||||
|
EAX = msr.tr2;
|
||||||
|
break;
|
||||||
|
/* TR3 - Cache Test Data */
|
||||||
|
case 0x00000005:
|
||||||
|
case 0x80000005:
|
||||||
|
EAX = msr.tr3;
|
||||||
|
break;
|
||||||
|
/* TR4 - Cache Test Tag */
|
||||||
|
case 0x00000006:
|
||||||
|
case 0x80000006:
|
||||||
|
EAX = msr.tr4;
|
||||||
|
break;
|
||||||
|
/* TR5 - Cache Test Control */
|
||||||
|
case 0x00000007:
|
||||||
|
case 0x80000007:
|
||||||
|
EAX = msr.tr5;
|
||||||
|
break;
|
||||||
|
/* TR6 - TLB Test Command */
|
||||||
|
case 0x00000008:
|
||||||
|
case 0x80000008:
|
||||||
|
EAX = msr.tr6;
|
||||||
|
break;
|
||||||
|
/* TR7 - TLB Test Data */
|
||||||
|
case 0x00000009:
|
||||||
|
case 0x80000009:
|
||||||
|
EAX = msr.tr7;
|
||||||
|
break;
|
||||||
|
/* TR9 - Branch Target Buffer Tag */
|
||||||
|
case 0x0000000b:
|
||||||
|
case 0x8000000b:
|
||||||
|
EAX = msr.tr9;
|
||||||
|
break;
|
||||||
|
/* TR10 - Branch Target Buffer Target */
|
||||||
|
case 0x0000000c:
|
||||||
|
case 0x8000000c:
|
||||||
|
EAX = msr.tr10;
|
||||||
|
break;
|
||||||
|
/* TR11 - Branch Target Buffer Control */
|
||||||
|
case 0x0000000d:
|
||||||
|
case 0x8000000d:
|
||||||
|
EAX = msr.tr11;
|
||||||
|
break;
|
||||||
|
/* TR12 - New Feature Control */
|
||||||
|
case 0x0000000e:
|
||||||
|
case 0x8000000e:
|
||||||
|
EAX = msr.tr12;
|
||||||
break;
|
break;
|
||||||
/* Time Stamp Counter */
|
/* Time Stamp Counter */
|
||||||
case 0x10:
|
case 0x00000010:
|
||||||
|
case 0x80000010:
|
||||||
EAX = tsc & 0xffffffff;
|
EAX = tsc & 0xffffffff;
|
||||||
EDX = tsc >> 32;
|
EDX = tsc >> 32;
|
||||||
break;
|
break;
|
||||||
|
/* Performance Monitor - Control and Event Select */
|
||||||
|
case 0x00000011:
|
||||||
|
case 0x80000011:
|
||||||
|
EAX = msr.cesr;
|
||||||
|
break;
|
||||||
|
/* Performance Monitor - Event Counter 0 */
|
||||||
|
case 0x00000012:
|
||||||
|
case 0x80000012:
|
||||||
|
EAX = msr.pmc[0] & 0xffffffff;
|
||||||
|
EDX = msr.pmc[0] >> 32;
|
||||||
|
break;
|
||||||
|
/* Performance Monitor - Event Counter 1 */
|
||||||
|
case 0x00000013:
|
||||||
|
case 0x80000013:
|
||||||
|
EAX = msr.pmc[1] & 0xffffffff;
|
||||||
|
EDX = msr.pmc[1] >> 32;
|
||||||
|
break;
|
||||||
|
/* Unknown */
|
||||||
|
case 0x00000014:
|
||||||
|
case 0x80000014:
|
||||||
|
if ((CPUID & 0xfff) <= 0x520)
|
||||||
|
goto pentium_invalid_rdmsr;
|
||||||
|
break;
|
||||||
|
/* Unknown, possibly paging-related; initial value is 0004h,
|
||||||
|
becomes 0008h once paging is enabled */
|
||||||
|
case 0x80000018:
|
||||||
|
EAX = ((cr0 & (1 << 31)) ? 0x00000008 : 0x00000004);
|
||||||
|
break;
|
||||||
|
/* Floating point - last prefetched opcode
|
||||||
|
bits 10-8: low three bits of first byte of FP instruction
|
||||||
|
bits 7-0: second byte of floating-point instruction */
|
||||||
|
case 0x80000019:
|
||||||
|
EAX = 0;
|
||||||
|
break;
|
||||||
|
/* Floating point - last executed non-control opcode */
|
||||||
|
case 0x8000001a:
|
||||||
|
EAX = 0;
|
||||||
|
break;
|
||||||
|
/* Floating point - last non-control exception opcode - part
|
||||||
|
of FSTENV/FSAVE'd environment */
|
||||||
|
case 0x8000001b:
|
||||||
|
EAX = msr.fp_last_xcpt;
|
||||||
|
break;
|
||||||
|
/* Unknown */
|
||||||
|
case 0x8000001c:
|
||||||
|
EAX = 0x00000004;
|
||||||
|
break;
|
||||||
|
/* Probe Mode Control */
|
||||||
|
case 0x8000001d:
|
||||||
|
EAX = msr.probe_ctl;
|
||||||
|
break;
|
||||||
|
/* Unknown, possibly scratchpad register */
|
||||||
|
case 0x8000001e:
|
||||||
|
EAX = msr.ecx8000001e;
|
||||||
|
break;
|
||||||
|
/* Unknown, possibly scratchpad register */
|
||||||
|
case 0x8000001f:
|
||||||
|
EAX = msr.ecx8000001f;
|
||||||
|
break;
|
||||||
|
/* Reserved/Unimplemented */
|
||||||
|
case 0x80000003:
|
||||||
|
case 0x8000000a:
|
||||||
|
case 0x8000000f:
|
||||||
|
case 0x80000015 ... 0x80000017:
|
||||||
|
EAX = (ECX & 0x1f) * 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pentium_invalid_rdmsr:
|
||||||
|
cpu_log("RDMSR: Invalid MSR: %08X\n", ECX);
|
||||||
|
x86gpf(NULL, 0);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
cpu_log("RDMSR: ECX = %08X, val = %08X%08X\n", ECX, EDX, EAX);
|
cpu_log("RDMSR: ECX = %08X, val = %08X%08X\n", ECX, EDX, EAX);
|
||||||
break;
|
break;
|
||||||
@@ -3368,20 +3509,150 @@ amd_k_invalid_wrmsr:
|
|||||||
case CPU_PENTIUM:
|
case CPU_PENTIUM:
|
||||||
case CPU_PENTIUMMMX:
|
case CPU_PENTIUMMMX:
|
||||||
cpu_log("WRMSR: ECX = %08X, val = %08X%08X\n", ECX, EDX, EAX);
|
cpu_log("WRMSR: ECX = %08X, val = %08X%08X\n", ECX, EDX, EAX);
|
||||||
switch (ECX) {
|
/* Filter out the upper 27 bits when ECX value is over 0x80000000, as per:
|
||||||
|
Ralf Brown, Pentium Model-Specific Registers and What They Reveal.
|
||||||
|
https://www.cs.cmu.edu/~ralf/papers/highmsr.html
|
||||||
|
But leave the bit 31 intact to be able to handle both low and high
|
||||||
|
MSRs in a single switch block. */
|
||||||
|
switch (ECX & (ECX > 0x7fffffff ? 0x8000001f : 0x7fffffff)) {
|
||||||
/* Machine Check Exception Address */
|
/* Machine Check Exception Address */
|
||||||
case 0x00:
|
case 0x00000000:
|
||||||
|
case 0x80000000:
|
||||||
/* Machine Check Exception Type */
|
/* Machine Check Exception Type */
|
||||||
case 0x01:
|
case 0x00000001:
|
||||||
|
case 0x80000001:
|
||||||
|
break;
|
||||||
|
/* TR1 - Parity Reversal Test Register */
|
||||||
|
case 0x00000002:
|
||||||
|
case 0x80000002:
|
||||||
|
msr.tr1 = EAX & 0x3fff;
|
||||||
|
break;
|
||||||
|
/* TR2 - Instruction Cache End Bit */
|
||||||
|
case 0x00000004:
|
||||||
|
case 0x80000004:
|
||||||
|
if (cpu_s->cpu_type == CPU_PENTIUMMMX)
|
||||||
|
goto pentium_invalid_wrmsr;
|
||||||
|
msr.tr2 = EAX & 0xf;
|
||||||
|
break;
|
||||||
|
/* TR3 - Cache Test Data */
|
||||||
|
case 0x00000005:
|
||||||
|
case 0x80000005:
|
||||||
|
msr.tr3 = EAX;
|
||||||
|
break;
|
||||||
|
/* TR4 - Cache Test Tag */
|
||||||
|
case 0x00000006:
|
||||||
|
case 0x80000006:
|
||||||
|
msr.tr4 = EAX & ((cpu_s->cpu_type == CPU_PENTIUMMMX) ? 0xffffff1f : 0xffffff07);
|
||||||
|
break;
|
||||||
|
/* TR5 - Cache Test Control */
|
||||||
|
case 0x00000007:
|
||||||
|
case 0x80000007:
|
||||||
|
msr.tr5 = EAX & ((cpu_s->cpu_type == CPU_PENTIUMMMX) ? 0x87fff : 0x7fff);
|
||||||
|
break;
|
||||||
|
/* TR6 - TLB Test Command */
|
||||||
|
case 0x00000008:
|
||||||
|
case 0x80000008:
|
||||||
|
msr.tr6 = EAX & 0xffffff07;
|
||||||
|
break;
|
||||||
|
/* TR7 - TLB Test Data */
|
||||||
|
case 0x00000009:
|
||||||
|
case 0x80000009:
|
||||||
|
msr.tr7 = EAX & ((cpu_s->cpu_type == CPU_PENTIUMMMX) ? 0xfffffc7f : 0xffffff9c);
|
||||||
|
break;
|
||||||
|
/* TR9 - Branch Target Buffer Tag */
|
||||||
|
case 0x0000000b:
|
||||||
|
case 0x8000000b:
|
||||||
|
msr.tr9 = EAX & ((cpu_s->cpu_type == CPU_PENTIUMMMX) ? 0xffffffff : 0xffffffc3);
|
||||||
|
break;
|
||||||
|
/* TR10 - Branch Target Buffer Target */
|
||||||
|
case 0x0000000c:
|
||||||
|
case 0x8000000c:
|
||||||
|
msr.tr10 = EAX;
|
||||||
|
break;
|
||||||
|
/* TR11 - Branch Target Buffer Control */
|
||||||
|
case 0x0000000d:
|
||||||
|
case 0x8000000d:
|
||||||
|
msr.tr11 = EAX & ((cpu_s->cpu_type >= CPU_PENTIUMMMX) ? 0x3001fcf : 0xfcf);
|
||||||
|
break;
|
||||||
|
/* TR12 - New Feature Control */
|
||||||
|
case 0x0000000e:
|
||||||
|
case 0x8000000e:
|
||||||
|
if (cpu_s->cpu_type == CPU_PENTIUMMMX)
|
||||||
|
temp = EAX & 0x38034f;
|
||||||
|
else if ((CPUID & 0xfff) >= 0x52b)
|
||||||
|
temp = EAX & 0x20435f;
|
||||||
|
else if ((CPUID & 0xfff) >= 0x520)
|
||||||
|
temp = EAX & 0x20035f;
|
||||||
|
else
|
||||||
|
temp = EAX & 0x20030f;
|
||||||
|
msr.tr12 = temp;
|
||||||
break;
|
break;
|
||||||
/* Time Stamp Counter */
|
/* Time Stamp Counter */
|
||||||
case 0x10:
|
case 0x00000010:
|
||||||
|
case 0x80000010:
|
||||||
tsc = EAX | ((uint64_t) EDX << 32);
|
tsc = EAX | ((uint64_t) EDX << 32);
|
||||||
break;
|
break;
|
||||||
/* BIOS Update Signature */
|
/* Performance Monitor - Control and Event Select */
|
||||||
case 0x8b:
|
case 0x00000011:
|
||||||
cpu_log("WRMSR: Invalid MSR: 0x8B\n");
|
case 0x80000011:
|
||||||
x86gpf(NULL, 0); /* Needed for Vista to correctly break on Pentium */
|
msr.cesr = EAX & 0x3ff03ff;
|
||||||
|
break;
|
||||||
|
/* Performance Monitor - Event Counter 0 */
|
||||||
|
case 0x00000012:
|
||||||
|
case 0x80000012:
|
||||||
|
msr.pmc[0] = EAX | ((uint64_t) EDX << 32);
|
||||||
|
break;
|
||||||
|
/* Performance Monitor - Event Counter 1 */
|
||||||
|
case 0x00000013:
|
||||||
|
case 0x80000013:
|
||||||
|
msr.pmc[1] = EAX | ((uint64_t) EDX << 32);
|
||||||
|
break;
|
||||||
|
/* Unknown */
|
||||||
|
case 0x00000014:
|
||||||
|
case 0x80000014:
|
||||||
|
if ((CPUID & 0xfff) <= 0x520)
|
||||||
|
goto pentium_invalid_wrmsr;
|
||||||
|
break;
|
||||||
|
/* Unknown, possibly paging-related; initial value is 0004h,
|
||||||
|
becomes 0008h once paging is enabled */
|
||||||
|
case 0x80000018:
|
||||||
|
/* Floating point - last prefetched opcode
|
||||||
|
bits 10-8: low three bits of first byte of FP instruction
|
||||||
|
bits 7-0: second byte of floating-point instruction */
|
||||||
|
case 0x80000019:
|
||||||
|
/* Floating point - last executed non-control opcode */
|
||||||
|
case 0x8000001a:
|
||||||
|
break;
|
||||||
|
/* Floating point - last non-control exception opcode - part
|
||||||
|
of FSTENV/FSAVE'd environment */
|
||||||
|
case 0x8000001b:
|
||||||
|
EAX = msr.fp_last_xcpt & 0x7ff;
|
||||||
|
break;
|
||||||
|
/* Unknown */
|
||||||
|
case 0x8000001c:
|
||||||
|
break;
|
||||||
|
/* Probe Mode Control */
|
||||||
|
case 0x8000001d:
|
||||||
|
EAX = msr.probe_ctl & 0x7;
|
||||||
|
break;
|
||||||
|
/* Unknown, possibly scratchpad register */
|
||||||
|
case 0x8000001e:
|
||||||
|
msr.ecx8000001e = EAX;
|
||||||
|
break;
|
||||||
|
/* Unknown, possibly scratchpad register */
|
||||||
|
case 0x8000001f:
|
||||||
|
msr.ecx8000001f = EAX;
|
||||||
|
break;
|
||||||
|
/* Reserved/Unimplemented */
|
||||||
|
case 0x80000003:
|
||||||
|
case 0x8000000a:
|
||||||
|
case 0x8000000f:
|
||||||
|
case 0x80000015 ... 0x80000017:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pentium_invalid_wrmsr:
|
||||||
|
cpu_log("WRMSR: Invalid MSR: %08X\n", ECX);
|
||||||
|
x86gpf(NULL, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@@ -249,9 +249,25 @@ typedef struct {
|
|||||||
uint64_t amd_l2aar; /* 0xc0000089 - K6-III and later */
|
uint64_t amd_l2aar; /* 0xc0000089 - K6-III and later */
|
||||||
|
|
||||||
/* Pentium/Pentium MMX MSRs */
|
/* Pentium/Pentium MMX MSRs */
|
||||||
uint32_t tr1; /* 0x00000002 - also on WinChip C6/2 */
|
uint64_t mcar; /* 0x00000000 - also on K5 and (R/W) K6 */
|
||||||
uint32_t tr12; /* 0x0000000e - also on WinChip C6/2 */
|
uint64_t mctr; /* 0x00000001 - also on K5 and (R/W) K6 */
|
||||||
uint32_t cesr; /* 0x00000011 - also on WinChip C6/2 */
|
uint32_t tr1; /* 0x00000002 - also on WinChip C6/2 */
|
||||||
|
uint32_t tr2; /* 0x00000004 - reserved on PMMX */
|
||||||
|
uint32_t tr3; /* 0x00000005 */
|
||||||
|
uint32_t tr4; /* 0x00000006 */
|
||||||
|
uint32_t tr5; /* 0x00000007 */
|
||||||
|
uint32_t tr6; /* 0x00000008 */
|
||||||
|
uint32_t tr7; /* 0x00000009 */
|
||||||
|
uint32_t tr9; /* 0x0000000b */
|
||||||
|
uint32_t tr10; /* 0x0000000c */
|
||||||
|
uint32_t tr11; /* 0x0000000d */
|
||||||
|
uint32_t tr12; /* 0x0000000e - also on WinChip C6/2 and K6 */
|
||||||
|
uint32_t cesr; /* 0x00000011 - also on WinChip C6/2 and Cx6x86MX */
|
||||||
|
uint64_t pmc[2]; /* 0x00000012, 0x00000013 - also on WinChip C6/2 and Cx6x86MX */
|
||||||
|
uint32_t fp_last_xcpt; /* 0x8000001b - undocumented */
|
||||||
|
uint32_t probe_ctl; /* 0x8000001d - undocumented */
|
||||||
|
uint32_t ecx8000001e; /* 0x8000001e - undocumented */
|
||||||
|
uint32_t ecx8000001f; /* 0x8000001f - undocumented */
|
||||||
|
|
||||||
/* Pentium Pro/II MSRs */
|
/* Pentium Pro/II MSRs */
|
||||||
uint64_t apic_base; /* 0x0000001b */
|
uint64_t apic_base; /* 0x0000001b */
|
||||||
@@ -559,7 +575,6 @@ extern double bus_timing;
|
|||||||
extern double isa_timing;
|
extern double isa_timing;
|
||||||
extern double pci_timing;
|
extern double pci_timing;
|
||||||
extern double agp_timing;
|
extern double agp_timing;
|
||||||
extern uint64_t pmc[2];
|
|
||||||
extern uint16_t temp_seg_data[4];
|
extern uint16_t temp_seg_data[4];
|
||||||
extern uint16_t cs_msr;
|
extern uint16_t cs_msr;
|
||||||
extern uint32_t esp_msr;
|
extern uint32_t esp_msr;
|
||||||
|
Reference in New Issue
Block a user