diff --git a/src/devices/cpu/i386/cpuidmsrs.hxx b/src/devices/cpu/i386/cpuidmsrs.hxx index f16868216a5..8ea746a8e19 100644 --- a/src/devices/cpu/i386/cpuidmsrs.hxx +++ b/src/devices/cpu/i386/cpuidmsrs.hxx @@ -430,8 +430,10 @@ 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 - data = 0; // when smm is not active + if (m_smm) + data = 0x1818181818181818; // when smm is active + else + data = 0; // when smm is not active } parse_mtrrfix(data, 0xa0000, 16); break; @@ -469,13 +471,16 @@ 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 - data = 0; // when smm is not active + if (m_smm) + data = 0x1818181818181818; // when smm is active + else + data = 0; // when smm is not active } else data = m_msr_mtrrfix[2]; diff --git a/src/devices/cpu/i386/i386.cpp b/src/devices/cpu/i386/i386.cpp index 6256b4de996..3c68bbf1471 100644 --- a/src/devices/cpu/i386/i386.cpp +++ b/src/devices/cpu/i386/i386.cpp @@ -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()) @@ -4023,7 +4020,7 @@ void i386_device::pentium_smi() m_sreg[DS].base = m_sreg[ES].base = m_sreg[FS].base = m_sreg[GS].base = m_sreg[SS].base = 0x00000000; m_sreg[DS].limit = m_sreg[ES].limit = m_sreg[FS].limit = m_sreg[GS].limit = m_sreg[SS].limit = 0xffffffff; m_sreg[DS].flags = m_sreg[ES].flags = m_sreg[FS].flags = m_sreg[GS].flags = m_sreg[SS].flags = 0x8093; - m_sreg[DS].valid = m_sreg[ES].valid = m_sreg[FS].valid = m_sreg[GS].valid = m_sreg[SS].valid =true; + m_sreg[DS].valid = m_sreg[ES].valid = m_sreg[FS].valid = m_sreg[GS].valid = m_sreg[SS].valid = true; m_sreg[CS].selector = 0x3000; // pentium only, ppro sel = smbase >> 4 m_sreg[CS].base = m_smbase; m_sreg[CS].limit = 0xffffffff; @@ -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; diff --git a/src/devices/cpu/i386/i386.h b/src/devices/cpu/i386/i386.h index 42eed546f41..4a691f9a1e7 100644 --- a/src/devices/cpu/i386/i386.h +++ b/src/devices/cpu/i386/i386.h @@ -72,6 +72,10 @@ protected: virtual std::unique_ptr 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(address); } virtual u16 mem_pr16(offs_t address) override { return opcode_read_cache(address); } diff --git a/src/devices/cpu/i386/i386priv.h b/src/devices/cpu/i386/i386priv.h index 0343cf74ef1..e67665ecbe8 100644 --- a/src/devices/cpu/i386/i386priv.h +++ b/src/devices/cpu/i386/i386priv.h @@ -166,14 +166,14 @@ enum enum { /* mmx registers aliased to x87 ones */ - MMX_MM0=X87_ST0, - MMX_MM1=X87_ST1, - MMX_MM2=X87_ST2, - MMX_MM3=X87_ST3, - MMX_MM4=X87_ST4, - MMX_MM5=X87_ST5, - MMX_MM6=X87_ST6, - MMX_MM7=X87_ST7 + MMX_MM0 = X87_ST0, + MMX_MM1 = X87_ST1, + MMX_MM2 = X87_ST2, + MMX_MM3 = X87_ST3, + MMX_MM4 = X87_ST4, + MMX_MM5 = X87_ST5, + MMX_MM6 = X87_ST6, + MMX_MM7 = X87_ST7 }; enum smram @@ -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]; @@ -281,7 +287,7 @@ union MMX_REG { int16_t s[4]; uint8_t b[8]; int8_t c[8]; - float f[2]; + float f[2]; uint64_t q; int64_t l; }; diff --git a/src/devices/cpu/i386/pentops.hxx b/src/devices/cpu/i386/pentops.hxx index b44ce8c40ed..6822dcb7b15 100644 --- a/src/devices/cpu/i386/pentops.hxx +++ b/src/devices/cpu/i386/pentops.hxx @@ -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)