Added experimental 286 task switching support, patch from Greatpsycho.
This commit is contained in:
176
src/CPU/x86seg.c
176
src/CPU/x86seg.c
@@ -25,8 +25,6 @@
|
|||||||
#include "x86.h"
|
#include "x86.h"
|
||||||
#include "386.h"
|
#include "386.h"
|
||||||
#include "386_common.h"
|
#include "386_common.h"
|
||||||
#undef readmemb
|
|
||||||
#define readmemb(a) ((readlookup2[(a)>>12]==-1)?readmembl(a):*(uint8_t *)(readlookup2[(a) >> 12] + (a)))
|
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
|
|
||||||
/*Controls whether the accessed bit in a descriptor is set when CS is loaded.*/
|
/*Controls whether the accessed bit in a descriptor is set when CS is loaded.*/
|
||||||
@@ -736,6 +734,7 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case 0x100: /*286 Task gate*/
|
||||||
case 0x900: /*386 Task gate*/
|
case 0x900: /*386 Task gate*/
|
||||||
cpu_state.pc=oxpc;
|
cpu_state.pc=oxpc;
|
||||||
cpl_override=1;
|
cpl_override=1;
|
||||||
@@ -2125,11 +2124,14 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32)
|
|||||||
|
|
||||||
uint16_t segdat2[4];
|
uint16_t segdat2[4];
|
||||||
|
|
||||||
base=segdat[1]|((segdat[2]&0xFF)<<16)|((segdat[3]>>8)<<24);
|
base=segdat[1]|((segdat[2]&0xFF)<<16);
|
||||||
limit=segdat[0]|((segdat[3]&0xF)<<16);
|
limit=segdat[0];
|
||||||
|
|
||||||
if (is386)
|
if (is32)
|
||||||
{
|
{
|
||||||
|
base |= (segdat[3]>>8)<<24;
|
||||||
|
limit |= (segdat[3]&0xF)<<16;
|
||||||
|
|
||||||
new_cr3=readmeml(base,0x1C);
|
new_cr3=readmeml(base,0x1C);
|
||||||
new_pc=readmeml(base,0x20);
|
new_pc=readmeml(base,0x20);
|
||||||
new_flags=readmeml(base,0x24);
|
new_flags=readmeml(base,0x24);
|
||||||
@@ -2215,12 +2217,12 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32)
|
|||||||
ldt.seg=new_ldt;
|
ldt.seg=new_ldt;
|
||||||
templ=(ldt.seg&~7)+gdt.base;
|
templ=(ldt.seg&~7)+gdt.base;
|
||||||
ldt.limit=readmemw(0,templ);
|
ldt.limit=readmemw(0,templ);
|
||||||
if (readmemb(templ+6)&0x80)
|
if (readmemb(0,templ+6)&0x80)
|
||||||
{
|
{
|
||||||
ldt.limit<<=12;
|
ldt.limit<<=12;
|
||||||
ldt.limit|=0xFFF;
|
ldt.limit|=0xFFF;
|
||||||
}
|
}
|
||||||
ldt.base=(readmemw(0,templ+2))|(readmemb(templ+4)<<16)|(readmemb(templ+7)<<24);
|
ldt.base=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16)|(readmemb(0,templ+7)<<24);
|
||||||
|
|
||||||
if (eflags&VM_FLAG)
|
if (eflags&VM_FLAG)
|
||||||
{
|
{
|
||||||
@@ -2311,9 +2313,165 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
resetx86();
|
new_pc=readmemw(base,0x0E);
|
||||||
}
|
new_flags=readmemw(base,0x10);
|
||||||
|
|
||||||
|
new_eax=readmemw(base,0x12);
|
||||||
|
new_ecx=readmemw(base,0x14);
|
||||||
|
new_edx=readmemw(base,0x16);
|
||||||
|
new_ebx=readmemw(base,0x18);
|
||||||
|
new_esp=readmemw(base,0x1A);
|
||||||
|
new_ebp=readmemw(base,0x1C);
|
||||||
|
new_esi=readmemw(base,0x1E);
|
||||||
|
new_edi=readmemw(base,0x20);
|
||||||
|
|
||||||
|
new_es=readmemw(base,0x22);
|
||||||
|
new_cs=readmemw(base,0x24);
|
||||||
|
new_ss=readmemw(base,0x26);
|
||||||
|
new_ds=readmemw(base,0x28);
|
||||||
|
new_ldt=readmemw(base,0x2A);
|
||||||
|
|
||||||
|
if (cpu_state.abrt) return;
|
||||||
|
if (optype==JMP || optype==OPTYPE_INT)
|
||||||
|
{
|
||||||
|
if (tr.seg&4) tempw=readmemw(ldt.base,(tr.seg&~7)+4);
|
||||||
|
else tempw=readmemw(gdt.base,(tr.seg&~7)+4);
|
||||||
|
if (cpu_state.abrt) return;
|
||||||
|
tempw&=~0x200;
|
||||||
|
if (tr.seg&4) writememw(ldt.base,(tr.seg&~7)+4,tempw);
|
||||||
|
else writememw(gdt.base,(tr.seg&~7)+4,tempw);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optype==IRET) flags&=~NT_FLAG;
|
||||||
|
|
||||||
|
cpu_386_flags_rebuild();
|
||||||
|
writememw(tr.base,0x0E,cpu_state.pc);
|
||||||
|
writememw(tr.base,0x10,flags);
|
||||||
|
|
||||||
|
writememw(tr.base,0x12,AX);
|
||||||
|
writememw(tr.base,0x14,CX);
|
||||||
|
writememw(tr.base,0x16,DX);
|
||||||
|
writememw(tr.base,0x18,BX);
|
||||||
|
writememw(tr.base,0x1A,SP);
|
||||||
|
writememw(tr.base,0x1C,BP);
|
||||||
|
writememw(tr.base,0x1E,SI);
|
||||||
|
writememw(tr.base,0x20,DI);
|
||||||
|
|
||||||
|
writememw(tr.base,0x22,ES);
|
||||||
|
writememw(tr.base,0x24,CS);
|
||||||
|
writememw(tr.base,0x26,SS);
|
||||||
|
writememw(tr.base,0x28,DS);
|
||||||
|
writememw(tr.base,0x2A,ldt.seg);
|
||||||
|
|
||||||
|
if (optype==OPTYPE_INT)
|
||||||
|
{
|
||||||
|
writememw(base,0,tr.seg);
|
||||||
|
new_flags|=NT_FLAG;
|
||||||
|
}
|
||||||
|
if (cpu_state.abrt) return;
|
||||||
|
if (optype==JMP || optype==OPTYPE_INT)
|
||||||
|
{
|
||||||
|
if (tr.seg&4) tempw=readmemw(ldt.base,(seg&~7)+4);
|
||||||
|
else tempw=readmemw(gdt.base,(seg&~7)+4);
|
||||||
|
if (cpu_state.abrt) return;
|
||||||
|
tempw|=0x200;
|
||||||
|
if (tr.seg&4) writememw(ldt.base,(seg&~7)+4,tempw);
|
||||||
|
else writememw(gdt.base,(seg&~7)+4,tempw);
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu_state.pc=new_pc;
|
||||||
|
flags=new_flags;
|
||||||
|
cpu_386_flags_extract();
|
||||||
|
|
||||||
|
ldt.seg=new_ldt;
|
||||||
|
templ=(ldt.seg&~7)+gdt.base;
|
||||||
|
ldt.limit=readmemw(0,templ);
|
||||||
|
ldt.base=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16);
|
||||||
|
|
||||||
|
if (!(new_cs&~3))
|
||||||
|
{
|
||||||
|
pclog("TS loading null CS\n");
|
||||||
|
x86gpf(NULL,0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addr=new_cs&~7;
|
||||||
|
if (new_cs&4)
|
||||||
|
{
|
||||||
|
if (addr>=ldt.limit)
|
||||||
|
{
|
||||||
|
pclog("Bigger than LDT limit %04X %04X %04X TS\n",new_cs,ldt.limit,addr);
|
||||||
|
x86gpf(NULL,0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addr+=ldt.base;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (addr>=gdt.limit)
|
||||||
|
{
|
||||||
|
pclog("Bigger than GDT limit %04X %04X TS\n",new_cs,gdt.limit);
|
||||||
|
x86gpf(NULL,0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
addr+=gdt.base;
|
||||||
|
}
|
||||||
|
segdat2[0]=readmemw(0,addr);
|
||||||
|
segdat2[1]=readmemw(0,addr+2);
|
||||||
|
segdat2[2]=readmemw(0,addr+4);
|
||||||
|
segdat2[3]=readmemw(0,addr+6);
|
||||||
|
if (!(segdat2[2]&0x8000))
|
||||||
|
{
|
||||||
|
pclog("TS loading CS not present\n");
|
||||||
|
x86np("TS loading CS not present\n", new_cs & 0xfffc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (segdat2[2]&0x1F00)
|
||||||
|
{
|
||||||
|
case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/
|
||||||
|
if ((new_cs&3) != DPL2)
|
||||||
|
{
|
||||||
|
pclog("TS load CS non-conforming RPL != DPL");
|
||||||
|
x86gpf(NULL,new_cs&~3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/
|
||||||
|
if ((new_cs&3) < DPL2)
|
||||||
|
{
|
||||||
|
pclog("TS load CS non-conforming RPL < DPL");
|
||||||
|
x86gpf(NULL,new_cs&~3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pclog("TS load CS not code segment\n");
|
||||||
|
x86gpf(NULL,new_cs&~3);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CS=new_cs;
|
||||||
|
do_seg_load(&_cs, segdat2);
|
||||||
|
if (CPL==3 && oldcpl!=3) flushmmucache_cr3();
|
||||||
|
set_use32(0);
|
||||||
|
|
||||||
|
AX=new_eax;
|
||||||
|
CX=new_ecx;
|
||||||
|
DX=new_edx;
|
||||||
|
BX=new_ebx;
|
||||||
|
SP=new_esp;
|
||||||
|
BP=new_ebp;
|
||||||
|
SI=new_esi;
|
||||||
|
DI=new_edi;
|
||||||
|
|
||||||
|
if (output) pclog("Load ES %04X\n",new_es);
|
||||||
|
loadseg(new_es,&_es);
|
||||||
|
if (output) pclog("Load SS %04X\n",new_ss);
|
||||||
|
loadseg(new_ss,&_ss);
|
||||||
|
if (output) pclog("Load DS %04X\n",new_ds);
|
||||||
|
loadseg(new_ds,&_ds);
|
||||||
|
|
||||||
|
if (output) pclog("Resuming at %04X:%08X\n",CS,cpu_state.pc);
|
||||||
|
}
|
||||||
|
|
||||||
tr.seg=seg;
|
tr.seg=seg;
|
||||||
tr.base=base;
|
tr.base=base;
|
||||||
|
|||||||
Reference in New Issue
Block a user