i386.cpp: athlon xp now supports system management mode (nw)

This commit is contained in:
yz70s 2019-04-26 12:53:48 +02:00
parent 428542508d
commit 8320a30ff3
5 changed files with 165 additions and 122 deletions

View File

@ -430,7 +430,9 @@ void athlonxp_device::opcode_wrmsr(uint64_t data, bool &valid_msr)
m_msr_mtrrfix[2] = data;
if (m_msr_smm_mask & 1)
{
// data = 0x1818181818181818; // when smm is implemented
if (m_smm)
data = 0x1818181818181818; // when smm is active
else
data = 0; // when smm is not active
}
parse_mtrrfix(data, 0xa0000, 16);
@ -469,12 +471,15 @@ void athlonxp_device::opcode_wrmsr(uint64_t data, bool &valid_msr)
break;
case 0xC0010111: // SMM_BASE
m_msr_smm_base = (offs_t)data;
m_smbase = m_msr_smm_base;
break;
case 0xC0010113: // SMM_MASK
m_msr_smm_mask = data;
if (m_msr_smm_mask & 1)
{
// data = 0x1818181818181818; // when smm is implemented
if (m_smm)
data = 0x1818181818181818; // when smm is active
else
data = 0; // when smm is not active
}
else

View File

@ -1542,7 +1542,7 @@ void i386_device::i386_check_irq_line()
{
if(!m_smm && m_smi)
{
pentium_smi();
enter_smm();
return;
}
@ -3947,15 +3947,12 @@ void i386_device::device_reset()
CHANGE_PC(m_eip);
}
void i386_device::pentium_smi()
void i386_device::enter_smm()
{
uint32_t smram_state = m_smbase + 0xfe00;
uint32_t old_cr0 = m_cr[0];
uint32_t old_flags = get_flags();
if(m_smm)
return;
m_cr[0] &= ~(0x8000000d);
set_flags(2);
if(!m_smiact.isnull())
@ -4037,6 +4034,87 @@ void i386_device::pentium_smi()
CHANGE_PC(m_eip);
}
void i386_device::leave_smm()
{
uint32_t smram_state = m_smbase + 0xfe00;
// load state, no sanity checks anywhere
m_smbase = READ32(smram_state + SMRAM_SMBASE);
m_cr[4] = READ32(smram_state + SMRAM_IP5_CR4);
m_sreg[ES].limit = READ32(smram_state + SMRAM_IP5_ESLIM);
m_sreg[ES].base = READ32(smram_state + SMRAM_IP5_ESBASE);
m_sreg[ES].flags = READ32(smram_state + SMRAM_IP5_ESACC);
m_sreg[CS].limit = READ32(smram_state + SMRAM_IP5_CSLIM);
m_sreg[CS].base = READ32(smram_state + SMRAM_IP5_CSBASE);
m_sreg[CS].flags = READ32(smram_state + SMRAM_IP5_CSACC);
m_sreg[SS].limit = READ32(smram_state + SMRAM_IP5_SSLIM);
m_sreg[SS].base = READ32(smram_state + SMRAM_IP5_SSBASE);
m_sreg[SS].flags = READ32(smram_state + SMRAM_IP5_SSACC);
m_sreg[DS].limit = READ32(smram_state + SMRAM_IP5_DSLIM);
m_sreg[DS].base = READ32(smram_state + SMRAM_IP5_DSBASE);
m_sreg[DS].flags = READ32(smram_state + SMRAM_IP5_DSACC);
m_sreg[FS].limit = READ32(smram_state + SMRAM_IP5_FSLIM);
m_sreg[FS].base = READ32(smram_state + SMRAM_IP5_FSBASE);
m_sreg[FS].flags = READ32(smram_state + SMRAM_IP5_FSACC);
m_sreg[GS].limit = READ32(smram_state + SMRAM_IP5_GSLIM);
m_sreg[GS].base = READ32(smram_state + SMRAM_IP5_GSBASE);
m_sreg[GS].flags = READ32(smram_state + SMRAM_IP5_GSACC);
m_ldtr.flags = READ32(smram_state + SMRAM_IP5_LDTACC);
m_ldtr.limit = READ32(smram_state + SMRAM_IP5_LDTLIM);
m_ldtr.base = READ32(smram_state + SMRAM_IP5_LDTBASE);
m_gdtr.limit = READ32(smram_state + SMRAM_IP5_GDTLIM);
m_gdtr.base = READ32(smram_state + SMRAM_IP5_GDTBASE);
m_idtr.limit = READ32(smram_state + SMRAM_IP5_IDTLIM);
m_idtr.base = READ32(smram_state + SMRAM_IP5_IDTBASE);
m_task.limit = READ32(smram_state + SMRAM_IP5_TRLIM);
m_task.base = READ32(smram_state + SMRAM_IP5_TRBASE);
m_task.flags = READ32(smram_state + SMRAM_IP5_TRACC);
m_sreg[ES].selector = READ32(smram_state + SMRAM_ES);
m_sreg[CS].selector = READ32(smram_state + SMRAM_CS);
m_sreg[SS].selector = READ32(smram_state + SMRAM_SS);
m_sreg[DS].selector = READ32(smram_state + SMRAM_DS);
m_sreg[FS].selector = READ32(smram_state + SMRAM_FS);
m_sreg[GS].selector = READ32(smram_state + SMRAM_GS);
m_ldtr.segment = READ32(smram_state + SMRAM_LDTR);
m_task.segment = READ32(smram_state + SMRAM_TR);
m_dr[7] = READ32(smram_state + SMRAM_DR7);
m_dr[6] = READ32(smram_state + SMRAM_DR6);
REG32(EAX) = READ32(smram_state + SMRAM_EAX);
REG32(ECX) = READ32(smram_state + SMRAM_ECX);
REG32(EDX) = READ32(smram_state + SMRAM_EDX);
REG32(EBX) = READ32(smram_state + SMRAM_EBX);
REG32(ESP) = READ32(smram_state + SMRAM_ESP);
REG32(EBP) = READ32(smram_state + SMRAM_EBP);
REG32(ESI) = READ32(smram_state + SMRAM_ESI);
REG32(EDI) = READ32(smram_state + SMRAM_EDI);
m_eip = READ32(smram_state + SMRAM_EIP);
m_eflags = READ32(smram_state + SMRAM_EFLAGS);
m_cr[3] = READ32(smram_state + SMRAM_CR3);
m_cr[0] = READ32(smram_state + SMRAM_CR0);
m_CPL = (m_sreg[SS].flags >> 13) & 3; // cpl == dpl of ss
for (int i = 0; i <= GS; i++)
{
if (PROTECTED_MODE && !V8086_MODE)
{
m_sreg[i].valid = m_sreg[i].selector ? true : false;
m_sreg[i].d = (m_sreg[i].flags & 0x4000) ? 1 : 0;
}
else
m_sreg[i].valid = true;
}
if (!m_smiact.isnull())
m_smiact(false);
m_smm = false;
CHANGE_PC(m_eip);
m_nmi_masked = false;
}
void i386_device::execute_set_input(int irqline, int state)
{
if ( irqline == INPUT_LINE_A20 )
@ -4763,7 +4841,7 @@ void athlonxp_device::device_reset()
m_memory_ranges_1m[n] = 0;
m_msr_top_mem = 1024 * 1024;
m_msr_sys_cfg = 0;
m_msr_smm_base = 0x30000;
m_msr_smm_base = m_smbase;
m_msr_smm_mask = 0;
m_cpuid_max_input_value_eax = 0x01;
@ -4785,6 +4863,30 @@ device_memory_interface::space_config_vector athlonxp_device::memory_space_confi
};
}
void athlonxp_device::enter_smm()
{
u64 data;
if (m_msr_smm_mask & 1)
data = 0x1818181818181818; // when smm is active
else
data = m_msr_mtrrfix[2];
parse_mtrrfix(data, 0xa0000, 16);
i386_device::enter_smm();
}
void athlonxp_device::leave_smm()
{
u64 data;
i386_device::leave_smm();
if (m_msr_smm_mask & 1)
data = 0; // when smm is not active
else
data = m_msr_mtrrfix[2];
parse_mtrrfix(data, 0xa0000, 16);
}
void athlonxp_device::parse_mtrrfix(u64 mtrr, offs_t base, int kblock)
{
int nb = kblock / 4;

View File

@ -72,6 +72,10 @@ protected:
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
virtual int get_mode() const override;
// cpu-specific system management mode routines
virtual void enter_smm();
virtual void leave_smm();
// routines for opcodes whose operation can vary between cpu models
// default implementations usually just log an error message
virtual void opcode_cpuid();
@ -1504,7 +1508,6 @@ protected:
void i386_postload();
void i386_common_init();
void build_opcode_table(uint32_t features);
void pentium_smi();
void zero_state();
void i386_set_a20_line(int state);
@ -1644,6 +1647,8 @@ protected:
virtual void cache_clean() override;
virtual void device_start() override;
virtual void device_reset() override;
virtual void enter_smm() override;
virtual void leave_smm() override;
virtual u8 mem_pr8(offs_t address) override { return opcode_read_cache<u8, NATIVE_ENDIAN_VALUE_LE_BE(0, 3)>(address); }
virtual u16 mem_pr16(offs_t address) override { return opcode_read_cache<u16, NATIVE_ENDIAN_VALUE_LE_BE(0, 2)>(address); }

View File

@ -247,32 +247,38 @@ enum smram_intel_p5
};
/* Protected mode exceptions */
#define FAULT_UD 6 // Invalid Opcode
#define FAULT_NM 7 // Coprocessor not available
#define FAULT_DF 8 // Double Fault
#define FAULT_TS 10 // Invalid TSS
#define FAULT_NP 11 // Segment or Gate not present
#define FAULT_SS 12 // Stack fault
#define FAULT_GP 13 // General Protection Fault
#define FAULT_PF 14 // Page Fault
#define FAULT_MF 16 // Match (Coprocessor) Fault
enum pm_faults
{
FAULT_UD = 6, // Invalid Opcode
FAULT_NM = 7, // Coprocessor not available
FAULT_DF = 8, // Double Fault
FAULT_TS = 10, // Invalid TSS
FAULT_NP = 11, // Segment or Gate not present
FAULT_SS = 12, // Stack fault
FAULT_GP = 13, // General Protection Fault
FAULT_PF = 14, // Page Fault
FAULT_MF = 16 // Match (Coprocessor) Fault
};
/* MXCSR Control and Status Register */
#define MXCSR_IE (1<<0) // Invalid Operation Flag
#define MXCSR_DE (1<<1) // Denormal Flag
#define MXCSR_ZE (1<<2) // Divide-by-Zero Flag
#define MXCSR_OE (1<<3) // Overflow Flag
#define MXCSR_UE (1<<4) // Underflow Flag
#define MXCSR_PE (1<<5) // Precision Flag
#define MXCSR_DAZ (1<<6) // Denormals Are Zeros
#define MXCSR_IM (1<<7) // Invalid Operation Mask
#define MXCSR_DM (1<<8) // Denormal Operation Mask
#define MXCSR_ZM (1<<9) // Divide-by-Zero Mask
#define MXCSR_OM (1<<10) // Overflow Mask
#define MXCSR_UM (1<<11) // Underflow Mask
#define MXCSR_PM (1<<12) // Precision Mask
#define MXCSR_RC (3<<13) // Rounding Control
#define MXCSR_FZ (1<<15) // Flush to Zero
enum mxcsr_bits
{
MXCSR_IE = 1 << 0, // Invalid Operation Flag
MXCSR_DE = 1 << 1, // Denormal Flag
MXCSR_ZE = 1 << 2, // Divide-by-Zero Flag
MXCSR_OE = 1 << 3, // Overflow Flag
MXCSR_UE = 1 << 4, // Underflow Flag
MXCSR_PE = 1 << 5, // Precision Flag
MXCSR_DAZ = 1 << 6, // Denormals Are Zeros
MXCSR_IM = 1 << 7, // Invalid Operation Mask
MXCSR_DM = 1 << 8, // Denormal Operation Mask
MXCSR_ZM = 1 << 9, // Divide-by-Zero Mask
MXCSR_OM = 1 << 10, // Overflow Mask
MXCSR_UM = 1 << 11, // Underflow Mask
MXCSR_PM = 1 << 12, // Precision Mask
MXCSR_RC = 3 << 13, // Rounding Control
MXCSR_FZ = 1 << 15 // Flush to Zero
};
union MMX_REG {
uint32_t d[2];

View File

@ -104,7 +104,6 @@ void i386_device::pentium_ud2() // Opcode 0x0f 0b
void i386_device::pentium_rsm()
{
uint32_t smram_state = m_smbase + 0xfe00;
if(!m_smm)
{
logerror("i386: Invalid RSM outside SMM at %08X\n", m_pc - 1);
@ -112,84 +111,10 @@ void i386_device::pentium_rsm()
return;
}
// load state, no sanity checks anywhere
m_smbase = READ32(smram_state+SMRAM_SMBASE);
m_cr[4] = READ32(smram_state+SMRAM_IP5_CR4);
m_sreg[ES].limit = READ32(smram_state+SMRAM_IP5_ESLIM);
m_sreg[ES].base = READ32(smram_state+SMRAM_IP5_ESBASE);
m_sreg[ES].flags = READ32(smram_state+SMRAM_IP5_ESACC);
m_sreg[CS].limit = READ32(smram_state+SMRAM_IP5_CSLIM);
m_sreg[CS].base = READ32(smram_state+SMRAM_IP5_CSBASE);
m_sreg[CS].flags = READ32(smram_state+SMRAM_IP5_CSACC);
m_sreg[SS].limit = READ32(smram_state+SMRAM_IP5_SSLIM);
m_sreg[SS].base = READ32(smram_state+SMRAM_IP5_SSBASE);
m_sreg[SS].flags = READ32(smram_state+SMRAM_IP5_SSACC);
m_sreg[DS].limit = READ32(smram_state+SMRAM_IP5_DSLIM);
m_sreg[DS].base = READ32(smram_state+SMRAM_IP5_DSBASE);
m_sreg[DS].flags = READ32(smram_state+SMRAM_IP5_DSACC);
m_sreg[FS].limit = READ32(smram_state+SMRAM_IP5_FSLIM);
m_sreg[FS].base = READ32(smram_state+SMRAM_IP5_FSBASE);
m_sreg[FS].flags = READ32(smram_state+SMRAM_IP5_FSACC);
m_sreg[GS].limit = READ32(smram_state+SMRAM_IP5_GSLIM);
m_sreg[GS].base = READ32(smram_state+SMRAM_IP5_GSBASE);
m_sreg[GS].flags = READ32(smram_state+SMRAM_IP5_GSACC);
m_ldtr.flags = READ32(smram_state+SMRAM_IP5_LDTACC);
m_ldtr.limit = READ32(smram_state+SMRAM_IP5_LDTLIM);
m_ldtr.base = READ32(smram_state+SMRAM_IP5_LDTBASE);
m_gdtr.limit = READ32(smram_state+SMRAM_IP5_GDTLIM);
m_gdtr.base = READ32(smram_state+SMRAM_IP5_GDTBASE);
m_idtr.limit = READ32(smram_state+SMRAM_IP5_IDTLIM);
m_idtr.base = READ32(smram_state+SMRAM_IP5_IDTBASE);
m_task.limit = READ32(smram_state+SMRAM_IP5_TRLIM);
m_task.base = READ32(smram_state+SMRAM_IP5_TRBASE);
m_task.flags = READ32(smram_state+SMRAM_IP5_TRACC);
m_sreg[ES].selector = READ32(smram_state+SMRAM_ES);
m_sreg[CS].selector = READ32(smram_state+SMRAM_CS);
m_sreg[SS].selector = READ32(smram_state+SMRAM_SS);
m_sreg[DS].selector = READ32(smram_state+SMRAM_DS);
m_sreg[FS].selector = READ32(smram_state+SMRAM_FS);
m_sreg[GS].selector = READ32(smram_state+SMRAM_GS);
m_ldtr.segment = READ32(smram_state+SMRAM_LDTR);
m_task.segment = READ32(smram_state+SMRAM_TR);
m_dr[7] = READ32(smram_state+SMRAM_DR7);
m_dr[6] = READ32(smram_state+SMRAM_DR6);
REG32(EAX) = READ32(smram_state+SMRAM_EAX);
REG32(ECX) = READ32(smram_state+SMRAM_ECX);
REG32(EDX) = READ32(smram_state+SMRAM_EDX);
REG32(EBX) = READ32(smram_state+SMRAM_EBX);
REG32(ESP) = READ32(smram_state+SMRAM_ESP);
REG32(EBP) = READ32(smram_state+SMRAM_EBP);
REG32(ESI) = READ32(smram_state+SMRAM_ESI);
REG32(EDI) = READ32(smram_state+SMRAM_EDI);
m_eip = READ32(smram_state+SMRAM_EIP);
m_eflags = READ32(smram_state+SMRAM_EFLAGS);
m_cr[3] = READ32(smram_state+SMRAM_CR3);
m_cr[0] = READ32(smram_state+SMRAM_CR0);
m_CPL = (m_sreg[SS].flags >> 13) & 3; // cpl == dpl of ss
for(int i = 0; i <= GS; i++)
{
if(PROTECTED_MODE && !V8086_MODE)
{
m_sreg[i].valid = m_sreg[i].selector ? true : false;
m_sreg[i].d = (m_sreg[i].flags & 0x4000) ? 1 : 0;
}
else
m_sreg[i].valid = true;
}
if(!m_smiact.isnull())
m_smiact(false);
m_smm = false;
CHANGE_PC(m_eip);
m_nmi_masked = false;
leave_smm();
if(m_smi_latched)
{
pentium_smi();
enter_smm();
return;
}
if(m_nmi_latched)