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                  }