i386: More page fault work. [Carl]
This commit is contained in:
parent
d83925d546
commit
f0553bafb5
@ -3099,7 +3099,7 @@ static CPU_TRANSLATE( i386 )
|
|||||||
if (space == AS_PROGRAM)
|
if (space == AS_PROGRAM)
|
||||||
{
|
{
|
||||||
if (cpustate->cr[0] & 0x80000000)
|
if (cpustate->cr[0] & 0x80000000)
|
||||||
result = translate_address(cpustate,0,address,&error);
|
result = translate_address(cpustate,-1,address,&error);
|
||||||
*address &= cpustate->a20_mask;
|
*address &= cpustate->a20_mask;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -381,7 +381,8 @@ INLINE UINT32 i386_translate(i386_state *cpustate, int segment, UINT32 ip)
|
|||||||
return cpustate->sreg[segment].base + ip;
|
return cpustate->sreg[segment].base + ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
INLINE int translate_address(i386_state *cpustate, bool rw, UINT32 *address, UINT32 *error)
|
// rwn; read = 0, write = 1, none = -1
|
||||||
|
INLINE int translate_address(i386_state *cpustate, int rwn, UINT32 *address, UINT32 *error)
|
||||||
{
|
{
|
||||||
UINT32 a = *address;
|
UINT32 a = *address;
|
||||||
UINT32 pdbr = cpustate->cr[3] & 0xfffff000;
|
UINT32 pdbr = cpustate->cr[3] & 0xfffff000;
|
||||||
@ -390,38 +391,80 @@ INLINE int translate_address(i386_state *cpustate, bool rw, UINT32 *address, UIN
|
|||||||
UINT32 offset = a & 0xfff;
|
UINT32 offset = a & 0xfff;
|
||||||
UINT32 page_entry;
|
UINT32 page_entry;
|
||||||
UINT32 ret = 1;
|
UINT32 ret = 1;
|
||||||
|
*error = 0;
|
||||||
|
|
||||||
// TODO: 4MB pages
|
// TODO: cr0 wp bit, 486 and higher
|
||||||
UINT32 page_dir = cpustate->program->read_dword(pdbr + directory * 4);
|
UINT32 page_dir = cpustate->program->read_dword(pdbr + directory * 4);
|
||||||
if (!(cpustate->cr[4] & 0x10))
|
if(page_dir & 1)
|
||||||
{
|
{
|
||||||
page_entry = cpustate->program->read_dword((page_dir & 0xfffff000) + (table * 4));
|
if (!(cpustate->cr[4] & 0x10))
|
||||||
if(!(page_entry & 1))
|
|
||||||
ret = 0;
|
|
||||||
else
|
|
||||||
*address = (page_entry & 0xfffff000) | offset;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (page_dir & 0x80)
|
|
||||||
{
|
|
||||||
if(!(page_dir & 1))
|
|
||||||
ret = 0;
|
|
||||||
else
|
|
||||||
*address = (page_dir & 0xffc00000) | (a & 0x003fffff);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
page_entry = cpustate->program->read_dword((page_dir & 0xfffff000) + (table * 4));
|
page_entry = cpustate->program->read_dword((page_dir & 0xfffff000) + (table * 4));
|
||||||
if(!(page_entry & 1))
|
if(!(page_entry & 1))
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
else if(!(page_entry & 2) && cpustate->CPL && (rwn == 1))
|
||||||
|
{
|
||||||
|
*error = 1;
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
if(!(page_dir & 0x20) && (rwn != -1))
|
||||||
|
cpustate->program->write_dword(pdbr + directory * 4, page_dir | 0x20);
|
||||||
|
if(!(page_entry & 0x40) && (rwn == 1))
|
||||||
|
cpustate->program->write_dword((page_dir & 0xfffff000) + (table * 4), page_entry | 0x60);
|
||||||
|
else if(!(page_entry & 0x20) && (rwn != -1))
|
||||||
|
cpustate->program->write_dword((page_dir & 0xfffff000) + (table * 4), page_entry | 0x20);
|
||||||
*address = (page_entry & 0xfffff000) | offset;
|
*address = (page_entry & 0xfffff000) | offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (page_dir & 0x80)
|
||||||
|
{
|
||||||
|
if(!(page_dir & 2) && cpustate->CPL && (rwn == 1))
|
||||||
|
{
|
||||||
|
*error = 1;
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!(page_dir & 0x40) && (rwn == 1))
|
||||||
|
cpustate->program->write_dword(pdbr + directory * 4, page_dir | 0x60);
|
||||||
|
else if(!(page_dir & 0x20) && (rwn != -1))
|
||||||
|
cpustate->program->write_dword(pdbr + directory * 4, page_dir | 0x20);
|
||||||
|
*address = (page_dir & 0xffc00000) | (a & 0x003fffff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
page_entry = cpustate->program->read_dword((page_dir & 0xfffff000) + (table * 4));
|
||||||
|
if(!(page_entry & 1))
|
||||||
|
ret = 0;
|
||||||
|
else if(!(page_entry & 2) && cpustate->CPL && (rwn == 1))
|
||||||
|
{
|
||||||
|
*error = 1;
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!(page_dir & 0x20) && (rwn != -1))
|
||||||
|
cpustate->program->write_dword(pdbr + directory * 4, page_dir | 0x20);
|
||||||
|
if(!(page_entry & 0x40) && (rwn == 1))
|
||||||
|
cpustate->program->write_dword((page_dir & 0xfffff000) + (table * 4), page_entry | 0x60);
|
||||||
|
else if(!(page_entry & 0x20) && (rwn != -1))
|
||||||
|
cpustate->program->write_dword((page_dir & 0xfffff000) + (table * 4), page_entry | 0x20);
|
||||||
|
*address = (page_entry & 0xfffff000) | offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
ret = 0;
|
||||||
if(!ret)
|
if(!ret)
|
||||||
{
|
{
|
||||||
*error = ((rw && 1)<<1) | ((cpustate->CPL==3)?1<<2:0);
|
if(rwn != -1)
|
||||||
|
*error |= ((rwn && 1)<<1) | ((cpustate->CPL==3)?1<<2:0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@ -436,7 +479,7 @@ INLINE void CHANGE_PC(i386_state *cpustate, UINT32 pc)
|
|||||||
|
|
||||||
if (cpustate->cr[0] & 0x80000000) // page translation enabled
|
if (cpustate->cr[0] & 0x80000000) // page translation enabled
|
||||||
{
|
{
|
||||||
translate_address(cpustate,0,&address,&error);
|
translate_address(cpustate,-1,&address,&error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -451,7 +494,7 @@ INLINE void NEAR_BRANCH(i386_state *cpustate, INT32 offs)
|
|||||||
|
|
||||||
if (cpustate->cr[0] & 0x80000000) // page translation enabled
|
if (cpustate->cr[0] & 0x80000000) // page translation enabled
|
||||||
{
|
{
|
||||||
translate_address(cpustate,0,&address,&error);
|
translate_address(cpustate,-1,&address,&error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user