From abc26792dd4b81f00c4c2d7e16d250e538688ace Mon Sep 17 00:00:00 2001 From: "K.Ohta" Date: Fri, 24 May 2019 05:29:56 +0900 Subject: [PATCH] [VM][I386] i386_sreg_load() : Replace IF-branch to CASE branch, to be faster. [VM][I386] i386priv.h : Add Segment descriptor table (GDT/LDT etc) bitfield description defines and bit value defines of sreg[foo].flags. [VM][I386] Some functions change to static from INLINE, these seems not be used heavily, used sometimes. --- source/src/vm/mame/emu/cpu/i386/i386.c | 187 +++++++++++++++-------------- source/src/vm/mame/emu/cpu/i386/i386priv.h | 119 +++++++++++++++++- 2 files changed, 217 insertions(+), 89 deletions(-) diff --git a/source/src/vm/mame/emu/cpu/i386/i386.c b/source/src/vm/mame/emu/cpu/i386/i386.c index a90690544..912d6e1a6 100644 --- a/source/src/vm/mame/emu/cpu/i386/i386.c +++ b/source/src/vm/mame/emu/cpu/i386/i386.c @@ -589,112 +589,123 @@ static void i386_sreg_load(i386_state *cpustate, UINT16 selector, UINT8 reg, boo } if(fault) *fault = true; - if(reg == SS) - { - I386_SREG stack; - - memset(&stack, 0, sizeof(stack)); - stack.selector = selector; - i386_load_protected_mode_segment(cpustate,&stack,NULL); - DPL = (stack.flags >> 5) & 0x03; - //logdebug("SReg load: SELECTOR=%04X FLAGS=%04X BASE=%08X LIMIT=%08X VALID=%s %s\n", stack.selector, stack.flags, stack.base, stack.limit, (stack.valid) ? "YES" : "NO", (stack.d == 0) ? "16bit SP" : "32bit ESP"); - if((selector & ~0x0003) == 0) +// if(reg == SS) + switch(reg) { + case SS: { - logerror("SReg Load (%08x): Selector is null.\n",cpustate->pc); - FAULT(FAULT_GP,0) - } - if(selector & 0x0004) // LDT - { - if((selector & ~0x0007) > cpustate->ldtr.limit) + I386_SREG stack; + + memset(&stack, 0, sizeof(stack)); + stack.selector = selector; + i386_load_protected_mode_segment(cpustate,&stack,NULL); + DPL = (stack.flags >> 5) & 0x03; + //logdebug("SReg load: SELECTOR=%04X FLAGS=%04X BASE=%08X LIMIT=%08X VALID=%s %s\n", stack.selector, stack.flags, stack.base, stack.limit, (stack.valid) ? "YES" : "NO", (stack.d == 0) ? "16bit SP" : "32bit ESP"); + if((selector & ~0x0003) == 0) { - logerror("SReg Load (SS)(%08x): Selector is out of LDT bounds.LDTR.limit=%4X : selector=%04X\n",cpustate->pc, cpustate->ldtr.limit, selector); - FAULT(FAULT_GP,selector & ~0x03) + logerror("SReg Load (%08x): Selector is null.\n",cpustate->pc); + FAULT(FAULT_GP,0) + } + if(selector & 0x0004) // LDT + { + if((selector & ~0x0007) > cpustate->ldtr.limit) + { + logerror("SReg Load (SS)(%08x): Selector is out of LDT bounds.LDTR.limit=%4X : selector=%04X\n",cpustate->pc, cpustate->ldtr.limit, selector); + FAULT(FAULT_GP,selector & ~0x03) + } } - } - else // GDT - { - if((selector & ~0x0007) > cpustate->gdtr.limit) + else // GDT { - logerror("SReg Load (%08x): Selector is out of bounds. GDT GDTR.limit=%04X : %04X\n",cpustate->pc, cpustate->gdtr.limit, selector); - FAULT(FAULT_GP,selector & ~0x03) + if((selector & ~0x0007) > cpustate->gdtr.limit) + { + logerror("SReg Load (%08x): Selector is out of bounds. GDT GDTR.limit=%04X : %04X\n",cpustate->pc, cpustate->gdtr.limit, selector); + FAULT(FAULT_GP,selector & ~0x03) + } } + if (RPL != CPL) + { + logerror("SReg Load (%08x): Selector RPL does not equal CPL.\n",cpustate->pc); + FAULT(FAULT_GP,selector & ~0x03) + } + if(((stack.flags & 0x0018) != 0x10) && (stack.flags & 0x0002) != 0) + { + logerror("SReg Load (%08x): Segment is not a writable data segment.\n",cpustate->pc); + FAULT(FAULT_GP,selector & ~0x03) + } + if(DPL != CPL) + { + logerror("SReg Load (%08x): Segment DPL does not equal CPL.\n",cpustate->pc); + FAULT(FAULT_GP,selector & ~0x03) + } + if(!(stack.flags & 0x0080)) + { + logerror("SReg Load (%08x): Segment is not present.\n",cpustate->pc); + FAULT(FAULT_SS,selector & ~0x03) + } } - if (RPL != CPL) - { - logerror("SReg Load (%08x): Selector RPL does not equal CPL.\n",cpustate->pc); - FAULT(FAULT_GP,selector & ~0x03) - } - if(((stack.flags & 0x0018) != 0x10) && (stack.flags & 0x0002) != 0) - { - logerror("SReg Load (%08x): Segment is not a writable data segment.\n",cpustate->pc); - FAULT(FAULT_GP,selector & ~0x03) - } - if(DPL != CPL) - { - logerror("SReg Load (%08x): Segment DPL does not equal CPL.\n",cpustate->pc); - FAULT(FAULT_GP,selector & ~0x03) - } - if(!(stack.flags & 0x0080)) + break; + case DS: + case ES: + case FS: + case GS: + //if(reg == DS || reg == ES || reg == FS || reg == GS) { - logerror("SReg Load (%08x): Segment is not present.\n",cpustate->pc); - FAULT(FAULT_SS,selector & ~0x03) - } - } - if(reg == DS || reg == ES || reg == FS || reg == GS) - { - I386_SREG desc; + I386_SREG desc; - if((selector & ~0x0003) == 0) - { - cpustate->sreg[reg].selector = selector; - i386_load_segment_descriptor(cpustate, reg ); - if(fault) *fault = false; - return; - } + if((selector & ~0x0003) == 0) + { + cpustate->sreg[reg].selector = selector; + i386_load_segment_descriptor(cpustate, reg ); + if(fault) *fault = false; + return; + } - memset(&desc, 0, sizeof(desc)); - desc.selector = selector; - i386_load_protected_mode_segment(cpustate,&desc,NULL); - DPL = (desc.flags >> 5) & 0x03; + memset(&desc, 0, sizeof(desc)); + desc.selector = selector; + i386_load_protected_mode_segment(cpustate,&desc,NULL); + DPL = (desc.flags >> 5) & 0x03; - if(selector & 0x0004) // LDT - { - if((selector & ~0x0007) > cpustate->ldtr.limit) + if(selector & 0x0004) // LDT { - logerror("SReg Load (other SS)(%08x): Selector is out of LDT bounds.LDTR.limit=%04X : %04X\n",cpustate->pc, cpustate->ldtr.limit, selector); - FAULT(FAULT_GP,selector & ~0x03) + if((selector & ~0x0007) > cpustate->ldtr.limit) + { + logerror("SReg Load (other SS)(%08x): Selector is out of LDT bounds.LDTR.limit=%04X : %04X\n",cpustate->pc, cpustate->ldtr.limit, selector); + FAULT(FAULT_GP,selector & ~0x03) + } } - } - else // GDT - { - if((selector & ~0x0007) > cpustate->gdtr.limit) + else // GDT { - logerror("SReg Load (%08x): Selector is out of GDT bounds.\n",cpustate->pc); - FAULT(FAULT_GP,selector & ~0x03) + if((selector & ~0x0007) > cpustate->gdtr.limit) + { + logerror("SReg Load (%08x): Selector is out of GDT bounds.\n",cpustate->pc); + FAULT(FAULT_GP,selector & ~0x03) + } } - } - if((desc.flags & 0x0018) != 0x10) - { - if((((desc.flags & 0x0002) != 0) && ((desc.flags & 0x0018) != 0x18)) || !(desc.flags & 0x10)) + if((desc.flags & 0x0018) != 0x10) { - logerror("SReg Load (%08x): Segment is not a data segment or readable code segment.\n",cpustate->pc); - FAULT(FAULT_GP,selector & ~0x03) + if((((desc.flags & 0x0002) != 0) && ((desc.flags & 0x0018) != 0x18)) || !(desc.flags & 0x10)) + { + logerror("SReg Load (%08x): Segment is not a data segment or readable code segment.\n",cpustate->pc); + FAULT(FAULT_GP,selector & ~0x03) + } } - } - if(((desc.flags & 0x0018) == 0x10) || ((!(desc.flags & 0x0004)) && ((desc.flags & 0x0018) == 0x18))) - { - // if data or non-conforming code segment - if((RPL > DPL) || (CPL > DPL)) + if(((desc.flags & 0x0018) == 0x10) || ((!(desc.flags & 0x0004)) && ((desc.flags & 0x0018) == 0x18))) { - logerror("SReg Load (%08x): Selector RPL or CPL is not less or equal to segment DPL.\n",cpustate->pc); - FAULT(FAULT_GP,selector & ~0x03) + // if data or non-conforming code segment + if((RPL > DPL) || (CPL > DPL)) + { + logerror("SReg Load (%08x): Selector RPL or CPL is not less or equal to segment DPL.\n",cpustate->pc); + FAULT(FAULT_GP,selector & ~0x03) + } } + if(!(desc.flags & 0x0080)) + { + logerror("SReg Load (%08x): Segment is not present.\n",cpustate->pc); + FAULT(FAULT_NP,selector & ~0x03) + } } - if(!(desc.flags & 0x0080)) - { - logerror("SReg Load (%08x): Segment is not present.\n",cpustate->pc); - FAULT(FAULT_NP,selector & ~0x03) - } + break; + default: + break; } cpustate->sreg[reg].selector = selector; @@ -702,7 +713,7 @@ static void i386_sreg_load(i386_state *cpustate, UINT16 selector, UINT8 reg, boo if(fault) *fault = false; } -/*static*/INLINE void i386_trap(i386_state *cpustate,int irq, int irq_gate, int trap_level) +static void i386_trap(i386_state *cpustate,int irq, int irq_gate, int trap_level) { /* I386 Interrupts/Traps/Faults: * diff --git a/source/src/vm/mame/emu/cpu/i386/i386priv.h b/source/src/vm/mame/emu/cpu/i386/i386priv.h index 2ce710ae5..3f9042d4e 100644 --- a/source/src/vm/mame/emu/cpu/i386/i386priv.h +++ b/source/src/vm/mame/emu/cpu/i386/i386priv.h @@ -296,6 +296,123 @@ enum smram_intel_p5 #define MXCSR_RC (3<<13) // Rounding Control #define MXCSR_FZ (1<<15) // Flush to Zero +// https://wiki.osdev.org/Global_Descriptor_Table +#define SREG_BITPOS_LIMIT_LOW 0 +#define SREG_BITPOS_LIMIT_HIGH 48 +#define SREG_BITSIZE_LIMIT_LOW 16 +#define SREG_BITSIZE_LIMIT_HIGH 4 +#define SREG_BITPOS_BASE_POS_LOW 16 +#define SREG_BITPOS_BASE_POS_MID 32 +#define SREG_BITPOS_BASE_POS_HIGH 56 +#define SREG_BITSIZE_BASE_LOW 16 +#define SREG_BITSIZE_BASE_MID 8 +#define SREG_BITSIZE_BASE_HIGH 8 +#define SREG_BITPOS_ACCESS_BYTE 40 +#define SREG_BITSIZE_ACCESS_BYTE 8 +#define SREG_BITPOS_FLAGS 52 +#define SREG_BITSIZE_FLAGS 4 + +// ARGS are pair32_t +INLINE UINT32 sreg_get_base(UINT32 high, UINT32 low) +{ + pair32_t ret; + pair32_t phigh; + pair32_t plow; + phigh.d = high; + plow.d = low; + ret.b.h3 = phigh.b.h3; /* high */ + ret.b.h2 = phigh.b.l; /* mid */ + ret.b.h = plow.b.h3; /* high of low */ + ret.b.l = plow.b.h2; /* low of low */ + return ret.d; +} + +INLINE UINT32 sreg_get_base_from_u64(UINT64 src) +{ + pair32_t ret; + pair64_t pa; + + pa.q = src; + ret.w.l = pa.w.h; + ret.b.h2 = pa.b.h4; + ret.b.h3 = pa.b.h7; + return ret.d; +} + +INLINE UINT32 sreg_get_limit(UINT32 high, UINT32 low) +{ + pair32_t ret; + pair32_t phigh; + pair32_t plow; + phigh.d = high; + plow.d = low; + + ret.w.l = plow.w.l; /* low */ + ret.b.h2 = phigh.b.h2 & 0x0f; + return ret.d; +} + +INLINE UINT32 sreg_get_limit_from_u64(UINT64 src) +{ + pair32_t ret; + pair64_t pa; + + pa.q = src; + ret.w.l = pa.w.l; + ret.b.h2 = pa.b.h6 & 0x0f; + return ret.d; +} + +INLINE UINT8 sreg_get_flags(UINT32 high) +{ + pair32_t phigh; + phigh.d = high; + return ((phigh.b.h2 & 0xf0) >> 4); +} + +INLINE UINT8 sreg_get_flags_from_u64(UINT64 src) +{ + pair32_t ret; + pair64_t pa; + + pa.q = src; + return ((pa.b.h6 & 0xf0) >> 4); +} + +INLINE UINT8 sreg_get_access_byte(UINT32 high) +{ + pair32_t phigh; + phigh.d = high; + return phigh.b.h; +} + +INLINE UINT8 sreg_get_access_byte_from_u64(UINT64 src) +{ + pair64_t pa; + + pa.q = src; + return pa.b.h5; +} + + +// IN SEGMENT DESCRIPTOR TABLE +// ACCESS BYTE BITFIELDS (bit40-47) +#define SREG_FLAGS_AC 0x0001 /* '1' is before accessed */ +#define SREG_FLAGS_RW 0x0002 /* READABLE for CODE SEGMENT/WRITABLE for DATA SEGMENT*/ +#define SREG_FLAGS_DC 0x0004 /* '1' to expand down, '0' to expand up */ +#define SREG_FLAGS_EX 0x0008 /* '1' to executable */ +#define SREG_FLAGS_NS 0x0010 /* '0' to system-segment */ +#define SREG_FLAGS_PRIV_LO 0x0020 /* PRIVILEGE (0 to 3) */ +#define SREG_FLAGS_PRIV_HI 0x0040 +#define SREG_FLAGS_PR 0x0080 /* '1' = valid segment */ + +// FLAGS (bit52-55) +#define SREG_FLAGS_RESV1 0x1000 +#define SREG_FLAGS_RESV2 0x2000 +#define SREG_FLAGS_SZ 0x4000 /* '1' at 32bit protected mode */ +#define SREG_FLAGS_GR 0x8000 /* '1' at limit multiplies to $1000 */ + + struct I386_SREG { UINT16 selector; UINT16 flags; @@ -728,7 +845,7 @@ INLINE UINT32 i386_translate(i386_state *cpustate, int segment, UINT32 ip, int r #define VTLB_FLAG_DIRTY 0x100 -INLINE vtlb_entry get_permissions(UINT32 pte, int wp) +vtlb_entry get_permissions(UINT32 pte, int wp) { vtlb_entry ret = VTLB_READ_ALLOWED | ((pte & 4) ? VTLB_USER_READ_ALLOWED : 0); if(!wp) -- 2.11.0