Fix for protection mode faults, makes 586 based things to work again by Carl (no whatsnew)

This commit is contained in:
Miodrag Milanovic 2012-02-02 14:58:18 +00:00
parent d8b59a82d2
commit fdca6f887c
2 changed files with 13 additions and 8 deletions

View File

@ -62,6 +62,7 @@ static void i386_load_protected_mode_segment(i386_state *cpustate, I386_SREG *se
if (seg->flags & 0x8000)
seg->limit = (seg->limit << 12) | 0xfff;
seg->d = (seg->flags & 0x4000) ? 1 : 0;
seg->valid = (seg->selector & ~3)?(true):(false);
}
static void i386_load_call_gate(i386_state* cpustate, I386_CALL_GATE *gate)
@ -107,12 +108,14 @@ static void i386_load_segment_descriptor(i386_state *cpustate, int segment )
cpustate->sreg[segment].limit = 0xffff;
cpustate->sreg[segment].flags = (segment == CS) ? 0x009a : 0x0092;
cpustate->sreg[segment].d = 0;
cpustate->sreg[segment].valid = true;
}
}
else
{
cpustate->sreg[segment].base = cpustate->sreg[segment].selector << 4;
cpustate->sreg[segment].d = 0;
cpustate->sreg[segment].valid = true;
if( segment == CS && !cpustate->performed_intersegment_jump )
cpustate->sreg[segment].base |= 0xfff00000;
@ -483,7 +486,6 @@ static void i386_protected_mode_sreg_load(i386_state *cpustate, UINT16 selector,
{
cpustate->sreg[reg].selector = selector;
i386_load_segment_descriptor(cpustate, reg );
// TODO: mark segment as invalid
return;
}
@ -1483,7 +1485,7 @@ static void i386_protected_mode_call(i386_state *cpustate, UINT16 seg, UINT32 of
}
if(selector & 0x04)
{
if((selector & ~0x07) >= cpustate->ldtr.limit)
if((selector & ~0x07) > cpustate->ldtr.limit)
{
logerror("CALL: Selector is past LDT limit.\n");
FAULT(FAULT_GP,selector & ~0x03) // #GP(selector)
@ -1491,7 +1493,7 @@ static void i386_protected_mode_call(i386_state *cpustate, UINT16 seg, UINT32 of
}
else
{
if((selector & ~0x07) >= cpustate->gdtr.limit)
if((selector & ~0x07) > cpustate->gdtr.limit)
{
logerror("CALL: Selector is past GDT limit.\n");
FAULT(FAULT_GP,selector & ~0x03) // #GP(selector)
@ -3006,10 +3008,12 @@ static CPU_RESET( i386 )
cpustate->sreg[CS].selector = 0xf000;
cpustate->sreg[CS].base = 0xffff0000;
cpustate->sreg[CS].limit = 0xffff;
cpustate->sreg[CS].valid = true;
cpustate->sreg[DS].base = cpustate->sreg[ES].base = cpustate->sreg[FS].base = cpustate->sreg[GS].base = cpustate->sreg[SS].base = 0x00000000;
cpustate->sreg[DS].limit = cpustate->sreg[ES].limit = cpustate->sreg[FS].limit = cpustate->sreg[GS].limit = cpustate->sreg[SS].limit = 0xffff;
cpustate->sreg[DS].flags = cpustate->sreg[ES].flags = cpustate->sreg[FS].flags = cpustate->sreg[GS].flags = cpustate->sreg[SS].flags = 0x0092;
cpustate->sreg[DS].valid = cpustate->sreg[ES].valid = cpustate->sreg[FS].valid = cpustate->sreg[GS].valid = cpustate->sreg[SS].valid =true;
cpustate->idtr.base = 0;
cpustate->idtr.limit = 0x3ff;

View File

@ -170,6 +170,7 @@ typedef struct {
UINT32 base;
UINT32 limit;
int d; // Operand size
bool valid;
} I386_SREG;
typedef struct
@ -395,14 +396,14 @@ INLINE UINT32 i386_translate(i386_state *cpustate, int segment, UINT32 ip, int r
// TODO: segment limit access size, execution permission, handle exception thrown from exception handler
if(PROTECTED_MODE && !V8086_MODE && (rwn != -1))
{
if(!(cpustate->sreg[segment].selector & ~3))
FAULT_THROW(FAULT_GP, 0);
if(!(cpustate->sreg[segment].valid))
FAULT_THROW((segment==SS)?FAULT_SS:FAULT_GP, 0);
if(i386_limit_check(cpustate, segment, ip))
FAULT_THROW(FAULT_GP, 0);
FAULT_THROW((segment==SS)?FAULT_SS:FAULT_GP, 0);
if((rwn == 0) && ((cpustate->sreg[segment].flags & 8) && !(cpustate->sreg[segment].flags & 2)))
FAULT_THROW(FAULT_GP, 0);
FAULT_THROW((segment==SS)?FAULT_SS:FAULT_GP, 0);
if((rwn == 1) && ((cpustate->sreg[segment].flags & 8) || !(cpustate->sreg[segment].flags & 2)))
FAULT_THROW(FAULT_GP, 0);
FAULT_THROW((segment==SS)?FAULT_SS:FAULT_GP, 0);
}
return cpustate->sreg[segment].base + ip;
}