PCem
changeset 96:30de9361da9a
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.
| author | TomW |
|---|---|
| date | Wed Apr 09 19:55:14 2014 +0100 |
| parents | da4d97ca11cf |
| children | 6ddadbcbcfe0 |
| files | src/386.c src/ide.c src/x86seg.c |
| diffstat | 3 files changed, 50 insertions(+), 21 deletions(-) [+] |
line diff
1.1 --- a/src/386.c Tue Apr 08 20:45:09 2014 +0100 1.2 +++ b/src/386.c Wed Apr 09 19:55:14 2014 +0100 1.3 @@ -86,6 +86,8 @@ 1.4 if ((a >> 12) == pccache) 1.5 return *((uint8_t *)&pccache2[a]); 1.6 pccache2 = getpccache(a); 1.7 + if (abrt) 1.8 + return; 1.9 pccache = a >> 12; 1.10 return *((uint8_t *)&pccache2[a]); 1.11 } 1.12 @@ -101,6 +103,8 @@ 1.13 } 1.14 if ((a>>12)==pccache) return *((uint16_t *)&pccache2[a]); 1.15 pccache2=getpccache(a); 1.16 + if (abrt) 1.17 + return; 1.18 pccache=a>>12; 1.19 return *((uint16_t *)&pccache2[a]); 1.20 }
2.1 --- a/src/ide.c Tue Apr 08 20:45:09 2014 +0100 2.2 +++ b/src/ide.c Wed Apr 09 19:55:14 2014 +0100 2.3 @@ -645,6 +645,7 @@ 2.4 void writeide(int ide_board, uint16_t addr, uint8_t val) 2.5 { 2.6 IDE *ide = &ide_drives[cur_ide[ide_board]]; 2.7 + IDE *ide_other = &ide_drives[cur_ide[ide_board] ^ 1]; 2.8 #ifndef RPCEMU_IDE 2.9 /* if (ide_board && (cr0&1) && !(eflags&VM_FLAG)) 2.10 { 2.11 @@ -671,27 +672,35 @@ 2.12 return; 2.13 2.14 case 0x1F1: /* Features */ 2.15 - ide->cylprecomp=val; 2.16 + ide->cylprecomp = val; 2.17 + ide_other->cylprecomp = val; 2.18 return; 2.19 2.20 case 0x1F2: /* Sector count */ 2.21 - ide->secount=val; 2.22 + ide->secount = val; 2.23 + ide_other->secount = val; 2.24 return; 2.25 2.26 case 0x1F3: /* Sector */ 2.27 - ide->sector=val; 2.28 - ide->lba_addr=(ide->lba_addr&0xFFFFF00)|val; 2.29 + ide->sector = val; 2.30 + ide->lba_addr = (ide->lba_addr & 0xFFFFF00) | val; 2.31 + ide_other->sector = val; 2.32 + ide_other->lba_addr = (ide_other->lba_addr & 0xFFFFF00) | val; 2.33 return; 2.34 2.35 case 0x1F4: /* Cylinder low */ 2.36 - ide->cylinder=(ide->cylinder&0xFF00)|val; 2.37 - ide->lba_addr=(ide->lba_addr&0xFFF00FF)|(val<<8); 2.38 + ide->cylinder = (ide->cylinder & 0xFF00) | val; 2.39 + ide->lba_addr = (ide->lba_addr & 0xFFF00FF) | (val << 8); 2.40 + ide_other->cylinder = (ide_other->cylinder&0xFF00) | val; 2.41 + ide_other->lba_addr = (ide_other->lba_addr&0xFFF00FF) | (val << 8); 2.42 // pclog("Write cylinder low %02X\n",val); 2.43 return; 2.44 2.45 case 0x1F5: /* Cylinder high */ 2.46 - ide->cylinder=(ide->cylinder&0xFF)|(val<<8); 2.47 - ide->lba_addr=(ide->lba_addr&0xF00FFFF)|(val<<16); 2.48 + ide->cylinder = (ide->cylinder & 0xFF) | (val << 8); 2.49 + ide->lba_addr = (ide->lba_addr & 0xF00FFFF) | (val << 16); 2.50 + ide_other->cylinder = (ide_other->cylinder & 0xFF) | (val << 8); 2.51 + ide_other->lba_addr = (ide_other->lba_addr & 0xF00FFFF) | (val << 16); 2.52 return; 2.53 2.54 case 0x1F6: /* Drive/Head */ 2.55 @@ -720,11 +729,14 @@ 2.56 ide = &ide_drives[cur_ide[ide_board]]; 2.57 } 2.58 2.59 - ide->head=val&0xF; 2.60 - ide->lba=val&0x40; 2.61 + ide->head = val & 0xF; 2.62 + ide->lba = val & 0x40; 2.63 + ide_other->head = val & 0xF; 2.64 + ide_other->lba = val & 0x40; 2.65 2.66 - ide->lba_addr=(ide->lba_addr&0x0FFFFFF)|((val&0xF)<<24); 2.67 - 2.68 + ide->lba_addr = (ide->lba_addr & 0x0FFFFFF) | ((val & 0xF) << 24); 2.69 + ide_other->lba_addr = (ide_other->lba_addr & 0x0FFFFFF)|((val & 0xF) << 24); 2.70 + 2.71 ide_irq_update(ide); 2.72 return; 2.73
3.1 --- a/src/x86seg.c Tue Apr 08 20:45:09 2014 +0100 3.2 +++ b/src/x86seg.c Wed Apr 09 19:55:14 2014 +0100 3.3 @@ -1996,7 +1996,7 @@ 3.4 // pclog("POP\n"); 3.5 newpc=POPL(); 3.6 seg=POPL(); 3.7 - tempflags=POPL(); if (abrt) return; 3.8 + tempflags=POPL(); if (abrt) { ESP = oldsp; return; } 3.9 // if (output) pclog("IRETD pop %08X %08X %08X\n",newpc,seg,tempflags); 3.10 if (is386 && ((tempflags>>16)&VM_FLAG)) 3.11 { 3.12 @@ -2007,7 +2007,7 @@ 3.13 segs[0]=POPL(); 3.14 segs[1]=POPL(); 3.15 segs[2]=POPL(); 3.16 - segs[3]=POPL(); if (abrt) return; 3.17 + segs[3]=POPL(); if (abrt) { ESP = oldsp; return; } 3.18 // pclog("Pop stack %04X:%04X\n",newss,newsp); 3.19 eflags=tempflags>>16; 3.20 loadseg(segs[0],&_es); 3.21 @@ -2043,13 +2043,14 @@ 3.22 { 3.23 newpc=POPW(); 3.24 seg=POPW(); 3.25 - tempflags=POPW(); if (abrt) return; 3.26 + tempflags=POPW(); if (abrt) { ESP = oldsp; return; } 3.27 } 3.28 // if (!is386) tempflags&=0xFFF; 3.29 // pclog("Returned to %04X:%08X %04X %04X %i\n",seg,newpc,flags,tempflags, ins); 3.30 if (!(seg&~3)) 3.31 { 3.32 pclog("IRET CS=0\n"); 3.33 + ESP = oldsp; 3.34 // dumpregs(); 3.35 // exit(-1); 3.36 x86gpf(NULL,0); 3.37 @@ -2063,6 +2064,7 @@ 3.38 if (addr>=ldt.limit) 3.39 { 3.40 pclog("Bigger than LDT limit %04X %04X IRET\n",seg,gdt.limit); 3.41 + ESP = oldsp; 3.42 x86gpf(NULL,seg&~3); 3.43 return; 3.44 } 3.45 @@ -2073,6 +2075,7 @@ 3.46 if (addr>=gdt.limit) 3.47 { 3.48 pclog("Bigger than GDT limit %04X %04X IRET\n",seg,gdt.limit); 3.49 + ESP = oldsp; 3.50 x86gpf(NULL,seg&~3); 3.51 return; 3.52 } 3.53 @@ -2081,6 +2084,7 @@ 3.54 if ((seg&3) < CPL) 3.55 { 3.56 pclog("IRET to lower level\n"); 3.57 + ESP = oldsp; 3.58 x86gpf(NULL,seg&~3); 3.59 return; 3.60 } 3.61 @@ -2088,7 +2092,7 @@ 3.62 segdat[0]=readmemw(0,addr); 3.63 segdat[1]=readmemw(0,addr+2); 3.64 segdat[2]=readmemw(0,addr+4); 3.65 - segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) { ESP=oldsp; return; } 3.66 + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) { ESP = oldsp; return; } 3.67 // pclog("Seg type %04X %04X\n",segdat[2]&0x1F00,segdat[2]); 3.68 3.69 switch (segdat[2]&0x1F00) 3.70 @@ -2097,6 +2101,7 @@ 3.71 if ((seg&3) != DPL) 3.72 { 3.73 pclog("IRET NC DPL %04X %04X %04X %04X %04X\n", seg, segdat[0], segdat[1], segdat[2], segdat[3]); 3.74 + ESP = oldsp; 3.75 // dumpregs(); 3.76 // exit(-1); 3.77 x86gpf(NULL,seg&~3); 3.78 @@ -2107,12 +2112,14 @@ 3.79 if ((seg&3) < DPL) 3.80 { 3.81 pclog("IRET C DPL\n"); 3.82 + ESP = oldsp; 3.83 x86gpf(NULL,seg&~3); 3.84 return; 3.85 } 3.86 break; 3.87 default: 3.88 pclog("IRET CS != code seg\n"); 3.89 + ESP = oldsp; 3.90 x86gpf(NULL,seg&~3); 3.91 // dumpregs(); 3.92 // exit(-1); 3.93 @@ -2121,7 +2128,7 @@ 3.94 if (!(segdat[2]&0x8000)) 3.95 { 3.96 pclog("IRET CS not present %i %04X %04X %04X\n",ins, segdat[0], segdat[1], segdat[2]); 3.97 - ESP=oldsp; 3.98 + ESP = oldsp; 3.99 x86np("IRET CS not present\n", seg & 0xfffc); 3.100 return; 3.101 } 3.102 @@ -2152,12 +2159,12 @@ 3.103 if (is32) 3.104 { 3.105 newsp=POPL(); 3.106 - newss=POPL(); if (abrt) return; 3.107 + newss=POPL(); if (abrt) { ESP = oldsp; return; } 3.108 } 3.109 else 3.110 { 3.111 newsp=POPW(); 3.112 - newss=POPW(); if (abrt) return; 3.113 + newss=POPW(); if (abrt) { ESP = oldsp; return; } 3.114 } 3.115 3.116 if (output) pclog("IRET load stack %04X:%04X\n",newss,newsp); 3.117 @@ -2165,6 +2172,7 @@ 3.118 if (!(newss&~3)) 3.119 { 3.120 pclog("IRET loading null SS\n"); 3.121 + ESP = oldsp; 3.122 x86gpf(NULL,newss&~3); 3.123 return; 3.124 } 3.125 @@ -2174,6 +2182,7 @@ 3.126 if (addr>=ldt.limit) 3.127 { 3.128 pclog("Bigger than LDT limit %04X %04X PMODEIRET SS\n",newss,gdt.limit); 3.129 + ESP = oldsp; 3.130 x86gpf(NULL,newss&~3); 3.131 return; 3.132 } 3.133 @@ -2184,6 +2193,7 @@ 3.134 if (addr>=gdt.limit) 3.135 { 3.136 pclog("Bigger than GDT limit %04X %04X PMODEIRET\n",newss,gdt.limit); 3.137 + ESP = oldsp; 3.138 x86gpf(NULL,newss&~3); 3.139 return; 3.140 } 3.141 @@ -2193,12 +2203,13 @@ 3.142 segdat2[0]=readmemw(0,addr); 3.143 segdat2[1]=readmemw(0,addr+2); 3.144 segdat2[2]=readmemw(0,addr+4); 3.145 - segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) { ESP=oldsp; return; } 3.146 + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) { ESP = oldsp; return; } 3.147 // pclog("IRET SS sd2 %04X\n",segdat2[2]); 3.148 // if (((newss & 3) != DPL) || (DPL2 != DPL)) 3.149 if ((newss & 3) != (seg & 3)) 3.150 { 3.151 pclog("IRET loading SS with wrong permissions %04X %04X\n", newss, seg); 3.152 + ESP = oldsp; 3.153 // dumpregs(); 3.154 // exit(-1); 3.155 x86gpf(NULL,newss&~3); 3.156 @@ -2207,19 +2218,21 @@ 3.157 if ((segdat2[2]&0x1A00)!=0x1200) 3.158 { 3.159 pclog("IRET loading SS wrong type\n"); 3.160 + ESP = oldsp; 3.161 x86gpf(NULL,newss&~3); 3.162 return; 3.163 } 3.164 if (DPL2 != (seg & 3)) 3.165 { 3.166 pclog("IRET loading SS with wrong permissions2 %i %i %04X %04X\n", DPL2, seg & 3, newss, seg); 3.167 - ESP=oldsp; 3.168 + ESP = oldsp; 3.169 x86gpf(NULL,newss&~3); 3.170 return; 3.171 } 3.172 if (!(segdat2[2]&0x8000)) 3.173 { 3.174 pclog("IRET loading SS not present\n"); 3.175 + ESP = oldsp; 3.176 x86np("IRET loading SS not present\n", newss & 0xfffc); 3.177 return; 3.178 }
