Restore correct ESP value on fault during IRET - fixes issues in at least Windows NT 3.51, NT 4.0, OS/2 2.0, OS/2 Warp. Thanks to SA1988.

Hack to mirror IDE register writes to both drives, fixes IDE issues on NT.
Fixed occasional PCem crash when accessing a faulting page, fixes crash in OS/2 2.0.
This commit is contained in:
TomW 2014-04-09 19:55:14 +01:00
commit 1493306d5e
3 changed files with 50 additions and 21 deletions

View file

@ -1996,7 +1996,7 @@ void pmodeiret(int is32)
// pclog("POP\n");
newpc=POPL();
seg=POPL();
tempflags=POPL(); if (abrt) return;
tempflags=POPL(); if (abrt) { ESP = oldsp; return; }
// if (output) pclog("IRETD pop %08X %08X %08X\n",newpc,seg,tempflags);
if (is386 && ((tempflags>>16)&VM_FLAG))
{
@ -2007,7 +2007,7 @@ void pmodeiret(int is32)
segs[0]=POPL();
segs[1]=POPL();
segs[2]=POPL();
segs[3]=POPL(); if (abrt) return;
segs[3]=POPL(); if (abrt) { ESP = oldsp; return; }
// pclog("Pop stack %04X:%04X\n",newss,newsp);
eflags=tempflags>>16;
loadseg(segs[0],&_es);
@ -2043,13 +2043,14 @@ void pmodeiret(int is32)
{
newpc=POPW();
seg=POPW();
tempflags=POPW(); if (abrt) return;
tempflags=POPW(); if (abrt) { ESP = oldsp; return; }
}
// if (!is386) tempflags&=0xFFF;
// pclog("Returned to %04X:%08X %04X %04X %i\n",seg,newpc,flags,tempflags, ins);
if (!(seg&~3))
{
pclog("IRET CS=0\n");
ESP = oldsp;
// dumpregs();
// exit(-1);
x86gpf(NULL,0);
@ -2063,6 +2064,7 @@ void pmodeiret(int is32)
if (addr>=ldt.limit)
{
pclog("Bigger than LDT limit %04X %04X IRET\n",seg,gdt.limit);
ESP = oldsp;
x86gpf(NULL,seg&~3);
return;
}
@ -2073,6 +2075,7 @@ void pmodeiret(int is32)
if (addr>=gdt.limit)
{
pclog("Bigger than GDT limit %04X %04X IRET\n",seg,gdt.limit);
ESP = oldsp;
x86gpf(NULL,seg&~3);
return;
}
@ -2081,6 +2084,7 @@ void pmodeiret(int is32)
if ((seg&3) < CPL)
{
pclog("IRET to lower level\n");
ESP = oldsp;
x86gpf(NULL,seg&~3);
return;
}
@ -2088,7 +2092,7 @@ void pmodeiret(int is32)
segdat[0]=readmemw(0,addr);
segdat[1]=readmemw(0,addr+2);
segdat[2]=readmemw(0,addr+4);
segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) { ESP=oldsp; return; }
segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) { ESP = oldsp; return; }
// pclog("Seg type %04X %04X\n",segdat[2]&0x1F00,segdat[2]);
switch (segdat[2]&0x1F00)
@ -2097,6 +2101,7 @@ void pmodeiret(int is32)
if ((seg&3) != DPL)
{
pclog("IRET NC DPL %04X %04X %04X %04X %04X\n", seg, segdat[0], segdat[1], segdat[2], segdat[3]);
ESP = oldsp;
// dumpregs();
// exit(-1);
x86gpf(NULL,seg&~3);
@ -2107,12 +2112,14 @@ void pmodeiret(int is32)
if ((seg&3) < DPL)
{
pclog("IRET C DPL\n");
ESP = oldsp;
x86gpf(NULL,seg&~3);
return;
}
break;
default:
pclog("IRET CS != code seg\n");
ESP = oldsp;
x86gpf(NULL,seg&~3);
// dumpregs();
// exit(-1);
@ -2121,7 +2128,7 @@ void pmodeiret(int is32)
if (!(segdat[2]&0x8000))
{
pclog("IRET CS not present %i %04X %04X %04X\n",ins, segdat[0], segdat[1], segdat[2]);
ESP=oldsp;
ESP = oldsp;
x86np("IRET CS not present\n", seg & 0xfffc);
return;
}
@ -2152,12 +2159,12 @@ void pmodeiret(int is32)
if (is32)
{
newsp=POPL();
newss=POPL(); if (abrt) return;
newss=POPL(); if (abrt) { ESP = oldsp; return; }
}
else
{
newsp=POPW();
newss=POPW(); if (abrt) return;
newss=POPW(); if (abrt) { ESP = oldsp; return; }
}
if (output) pclog("IRET load stack %04X:%04X\n",newss,newsp);
@ -2165,6 +2172,7 @@ void pmodeiret(int is32)
if (!(newss&~3))
{
pclog("IRET loading null SS\n");
ESP = oldsp;
x86gpf(NULL,newss&~3);
return;
}
@ -2174,6 +2182,7 @@ void pmodeiret(int is32)
if (addr>=ldt.limit)
{
pclog("Bigger than LDT limit %04X %04X PMODEIRET SS\n",newss,gdt.limit);
ESP = oldsp;
x86gpf(NULL,newss&~3);
return;
}
@ -2184,6 +2193,7 @@ void pmodeiret(int is32)
if (addr>=gdt.limit)
{
pclog("Bigger than GDT limit %04X %04X PMODEIRET\n",newss,gdt.limit);
ESP = oldsp;
x86gpf(NULL,newss&~3);
return;
}
@ -2193,12 +2203,13 @@ void pmodeiret(int is32)
segdat2[0]=readmemw(0,addr);
segdat2[1]=readmemw(0,addr+2);
segdat2[2]=readmemw(0,addr+4);
segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) { ESP=oldsp; return; }
segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) { ESP = oldsp; return; }
// pclog("IRET SS sd2 %04X\n",segdat2[2]);
// if (((newss & 3) != DPL) || (DPL2 != DPL))
if ((newss & 3) != (seg & 3))
{
pclog("IRET loading SS with wrong permissions %04X %04X\n", newss, seg);
ESP = oldsp;
// dumpregs();
// exit(-1);
x86gpf(NULL,newss&~3);
@ -2207,19 +2218,21 @@ void pmodeiret(int is32)
if ((segdat2[2]&0x1A00)!=0x1200)
{
pclog("IRET loading SS wrong type\n");
ESP = oldsp;
x86gpf(NULL,newss&~3);
return;
}
if (DPL2 != (seg & 3))
{
pclog("IRET loading SS with wrong permissions2 %i %i %04X %04X\n", DPL2, seg & 3, newss, seg);
ESP=oldsp;
ESP = oldsp;
x86gpf(NULL,newss&~3);
return;
}
if (!(segdat2[2]&0x8000))
{
pclog("IRET loading SS not present\n");
ESP = oldsp;
x86np("IRET loading SS not present\n", newss & 0xfffc);
return;
}