Finding out what's crashing Windows 95?

Emulation of old PCs, PC hardware, or PC peripherals.

Finding out what's crashing Windows 95?

Postby superfury » 2019-11-10 @ 21:56

As far as I know, all instructions should be correctly emulated(stepping through them).

The opcode tables are all fine. The protection checks and paging are also implemented fully according to the 80386/486/Pentium's programmer's reference manual.

Then, it still crashes when reaching 137:6622(16-bit code). It's trying to RETD to a kernel offset within the current segment. This causes a BSOD. The last line in the Windows bootlog.txt says "Initializing KERNEL".

Anyone knows how to find the issue that's causing this? Stuff like the programmer's reference manual don't add anything as it's implemented exactly as it says(the chapters on protection and instructions), although the segment algorithmics are combined in a big super-function that handles all cases at once(only diverging execution flow on faults(and returning to caller).

https://bitbucket.org/superfury/unipcem ... otection.c
It's the segmentWritten function that handles all segment writes(mov, jmp, call, stack switches(SS loads to be exact, called by switchStacks, segment loads after loading LDTR during TSS hardware-based task switching). The only difference between those is the isJMPorCALL parameter(0 for normal loads, low bits being 1 for JMP, 2 for CALL, 3 for IRET, 4 for RETF). Additional information can also be passed(e.g. alternate privilege level instead of CPL, special behaviour for certain load cases, ignore CPL checks).

Anyone can see if there's something wrong? Most functionality is in the segmentWritten and getsegment_seg functions(and a bit in the LOADDESCRIPTOR function).

Is there a good way to find out if there's an error in the privilege-related handling?
superfury
l33t
 
Posts: 3288
Joined: 2014-3-08 @ 11:25
Location: Netherlands

Re: Finding out what's crashing Windows 95?

Postby superfury » 2019-11-10 @ 23:42

Or even better. Is there any thorough documentation on x86 segment loading, processing, interrupts etc. that explains all checks done by the IA-32 CPUs in one big function-like or flow-chart format? Like how UniPCemu handles all segment loading for all situations using a big shared function(with only divergeances here and there for different cases to be applied). I can imagine that CPU implementations run the same way(sharing die for real processors)?

For some reason I can't find ANY reasonable documentation that explains all aspects in detail. I can't even remember how many times I've read that the RPL field of the CS selector is actually CPL itself, while in actuality the DPL field of the SS descriptor in it's descriptor cache is the CPL used instead(the CS.RPL field only being used during RETF/IRET, but there for programmer's convenience in all other cases).

Or looking at the 80386 programmers reference manual explaining interrupts in protected mode for 32-bit cases only, leaving out 16-bit protected mode compatibility in there entirely(thus Windows 3.x/9x would crash according to that or be undocumented entirely(which it isn't)).
superfury
l33t
 
Posts: 3288
Joined: 2014-3-08 @ 11:25
Location: Netherlands

Re: Finding out what's crashing Windows 95?

Postby superfury » 2019-11-12 @ 12:41

Hmmm... Tried 95C again. It hang during loading IOS at the start of the bootlog.

I tried finding invalid memory references(page faults while already parsing through the BIU(past the faultable stage). No such things were found.

So there's either some incorrect faulting behaviour for non-page faults(#GP,#SS etc.) or some really hidden CPU instruction fetch/execution bug.

Although execution bugs should be highly unlikely by now(as they're already verified by me for multiple times). And I've also checked for opcode bugs at the same time, which also seemed to match i386 documentation and execution(no invalid parsing of the execution flow).

Unless there's some hidden flag behaviour? Anyone knows of any untested by the test386.asm testsuite?
superfury
l33t
 
Posts: 3288
Joined: 2014-3-08 @ 11:25
Location: Netherlands

Re: Finding out what's crashing Windows 95?

Postby superfury » 2019-11-12 @ 13:14

This is the current segment write handler for all cases:
Code: Select all
/*

getsegment_seg: Gets a segment, if allowed, for protected mode.
parameters:
   whatsegment: For what segment is to be fetched?
   segment: The segment selector to get.
   isJMPorCALL: 0 for normal segment setting. 1 for JMP, 2 for CALL, 3 for IRET, 4 for RETF. bit7=Disable privilege level checking, bit8=Disable SAVEDESCRIPTOR writeback, bit9=task switch, bit10=Set EXT bit on faulting, bit 11=TSS Busy requirement(1=Busy, 0=Non-busy), bit 12=bit 13-14 are the CPL instead for privilege checks. bit13-14: used CPL, bit 15: don't throw #SS when set and not a present cause of the fault.
result:
   The segment when available, NULL on error or disallow.

*/

#define effectiveCPL() ((isJMPorCALL&0x1000)?((isJMPorCALL>>13)&3):getCPL())

sbyte touchSegment(int segment, word segmentval, SEGMENT_DESCRIPTOR *container, word isJMPorCALL)
{
   sbyte saveresult;
   if(GENERALSEGMENTPTR_P(container) && (getLoadedTYPE(container) != 2) && (CODEDATASEGMENTPTR_A(container) == 0) && ((isJMPorCALL&0x100)==0)) //Non-accessed loaded and needs to be set? Our reserved bit 8 in isJMPorCALL tells us not to cause writeback for accessed!
   {
      container->desc.AccessRights |= 1; //Set the accessed bit!
      if ((saveresult = SAVEDESCRIPTOR(segment, segmentval, container, isJMPorCALL))<=0) //Trigger writeback and errored out?
      {
         return saveresult;
      }
   }
   return 1; //Success!
}

SEGMENT_DESCRIPTOR *getsegment_seg(int segment, SEGMENT_DESCRIPTOR *dest, word *segmentval, word isJMPorCALL, byte *isdifferentCPL) //Get this corresponding segment descriptor (or LDT. For LDT, specify LDT register as segment) for loading into the segment descriptor cache!
{
   //byte newCPL = getCPL(); //New CPL after switching! Default: no change!
   SEGMENT_DESCRIPTOR LOADEDDESCRIPTOR, GATEDESCRIPTOR; //The descriptor holder/converter!
   memset(&LOADEDDESCRIPTOR, 0, sizeof(LOADEDDESCRIPTOR)); //Init!
   memset(&GATEDESCRIPTOR, 0, sizeof(GATEDESCRIPTOR)); //Init!
   word originalval=*segmentval; //Back-up of the original segment value!
   byte allowNP; //Allow #NP to be used?
   sbyte loadresult;
   byte privilegedone = 0; //Privilege already calculated?
   byte is_gated = 0; //Are we gated?
   byte is_TSS = 0; //Are we a TSS?
   byte callgatetype = 0; //Default: no call gate!

   if ((*segmentval&4) && (((GENERALSEGMENT_P(CPU[activeCPU].SEG_DESCRIPTOR[CPU_SEGMENT_LDTR])==0) && (segment!=CPU_SEGMENT_LDTR)) || (segment==CPU_SEGMENT_LDTR) || (segment==CPU_SEGMENT_TR))) //Invalid LDT segment and LDT is addressed or LDTR/TR in LDT?
   {
      //if ((segment == CPU_SEGMENT_SS) && (isJMPorCALL&0x200) && ((isJMPorCALL&0x8000)==0)) goto throwSSsegmentval;
   throwdescsegmentval:
      if (isJMPorCALL&0x200) //TSS is the cause?
      {
         THROWDESCTS(*segmentval,1,(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!         
      }
      else //Plain #GP?
      {
         THROWDESCGP(*segmentval,((isJMPorCALL&0x400)>>10),(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
      }
      return NULL; //We're an invalid TSS to execute!
   throwSSsegmentval:
      THROWDESCSS(*segmentval,((isJMPorCALL&0x400)>>10),(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
      return NULL; //We're an invalid value to execute!
   }

   if ((loadresult = LOADDESCRIPTOR(segment,*segmentval,&LOADEDDESCRIPTOR,isJMPorCALL))<=0) //Error loading current descriptor?
   {
      if (loadresult == 0) //Not already faulted?
      {
         //if ((segment == CPU_SEGMENT_SS) && (isJMPorCALL & 0x200) && ((isJMPorCALL & 0x8000) == 0)) goto throwSSsegmentval;
         goto throwdescsegmentval;
      }
      return NULL; //Error, by specified reason!
   }
   allowNP = ((segment==CPU_SEGMENT_DS) || (segment==CPU_SEGMENT_ES) || (segment==CPU_SEGMENT_FS) || (segment==CPU_SEGMENT_GS)); //Allow segment to be marked non-present(exception: values 0-3 with data segments)?

   if (((*segmentval&~3)==0)) //NULL GDT segment when not allowed?
   {
      if (segment==CPU_SEGMENT_LDTR) //in LDTR? We're valid!
      {
         goto validLDTR; //Skip all checks, and check out as valid! We're allowed on the LDTR only!
      }
      else //Skip checks: we're invalid to check any further!
      {
         if ((segment==CPU_SEGMENT_CS) || (segment==CPU_SEGMENT_TR) || (segment==CPU_SEGMENT_SS)) //Not allowed?
         {
            //if ((segment == CPU_SEGMENT_SS) && (isJMPorCALL & 0x200) && ((isJMPorCALL & 0x8000) == 0)) goto throwSSsegmentval;
            goto throwdescsegmentval; //Throw #GP error!
            return NULL; //Error, by specified reason!
         }
         else if (allowNP)
         {
            goto validLDTR; //Load NULL descriptor!
         }
      }
   }

   if ((isGateDescriptor(&LOADEDDESCRIPTOR)==1) && (segment == CPU_SEGMENT_CS) && (((isJMPorCALL&0x1FF)==1) || ((isJMPorCALL&0x1FF)==2)) && ((isJMPorCALL&0x200)==0)) //Handling of gate descriptors? Disable on task code/data segment loading!
   {
      is_gated = 1; //We're gated!
      memcpy(&GATEDESCRIPTOR, &LOADEDDESCRIPTOR, sizeof(GATEDESCRIPTOR)); //Copy the loaded descriptor to the GATE!
      //Check for invalid loads!
      switch (GENERALSEGMENT_TYPE(GATEDESCRIPTOR))
      {
      default: //Unknown type?
      case AVL_SYSTEM_INTERRUPTGATE16BIT:
      case AVL_SYSTEM_TRAPGATE16BIT:
      case AVL_SYSTEM_INTERRUPTGATE32BIT:
      case AVL_SYSTEM_TRAPGATE32BIT:
         /*
         if ((isJMPorCALL & 0x1FF) == 2) //CALL? It's an programmed interrupt call!
         {
            CPU_handleInterruptGate(((isJMPorCALL&0x400)>>10),(*segmentval & 4) ? EXCEPTION_TABLE_LDT : EXCEPTION_TABLE_GDT, (*segmentval & 0xFFF8), &LOADEDDESCRIPTOR.desc, REG_CS, REG_EIP, -2, 1); //Raise an interrupt instead!
            return NULL; //Abort: we're handled by the interrupt handler!
         }
         */ //80386 user manual CALL instruction reference says that interrupt and other gates being loaded end up with a General Protection fault.
         //JMP isn't valid for interrupt gates?
         //We're an invalid gate!
         goto throwdescsegmentval; //Throw #GP error!      
         return NULL; //Not present: invalid descriptor type loaded!
         break;
      case AVL_SYSTEM_TASKGATE: //Task gate?
      case AVL_SYSTEM_CALLGATE16BIT:
      case AVL_SYSTEM_CALLGATE32BIT:
         //Valid gate! Allow!
         break;
      }
      if ((MAX(effectiveCPL(), getRPL(*segmentval)) > GENERALSEGMENT_DPL(GATEDESCRIPTOR)) && ((isJMPorCALL&0x1FF)!=3)) //Gate has too high a privilege level? Only when not an IRET(always allowed)!
      {
         goto throwdescsegmentval; //Throw error!
         return NULL; //We are a lower privilege level, so don't load!            
      }
      if (GENERALSEGMENT_P(GATEDESCRIPTOR)==0) //Not present loaded into non-data segment register?
      {
         if (segment==CPU_SEGMENT_SS) //Stack fault?
         {
            THROWDESCSS(*segmentval,(isJMPorCALL&0x200)?1:(((isJMPorCALL&0x400)>>10)),(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Stack fault!
         }
         else
         {
            THROWDESCNP(*segmentval, (isJMPorCALL&0x200)?1:(((isJMPorCALL&0x400)>>10)),(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
         }
         return NULL; //We're an invalid TSS to execute!
      }

      *segmentval = GATEDESCRIPTOR.desc.selector; //We're loading this segment now, with requesting privilege!

      if (((*segmentval&~3)==0)) //NULL GDT segment when not allowed?
      {
         goto throwdescsegmentval; //Throw #GP(0) error!
         return NULL; //Abort!
      }

      if ((loadresult = LOADDESCRIPTOR(segment, *segmentval, &LOADEDDESCRIPTOR,isJMPorCALL))<=0) //Error loading current descriptor?
      {
         if (loadresult == 0) //Not faulted already?
         {
            goto throwdescsegmentval; //Throw error!
         }
         return NULL; //Error, by specified reason!
      }
      privilegedone = 1; //Privilege has been precalculated!
      if (GENERALSEGMENT_TYPE(GATEDESCRIPTOR) == AVL_SYSTEM_TASKGATE) //Task gate?
      {
         if (segment != CPU_SEGMENT_CS) //Not code? We're not a task switch! We're trying to load the task segment into a data register. This is illegal! TR doesn't support Task Gates directly(hardware only)!
         {
            goto throwdescsegmentval; //Throw error!
            return NULL; //Don't load!
         }
      }
      else //Normal descriptor?
      {
         if (GENERALSEGMENT_S(LOADEDDESCRIPTOR)==0) goto throwdescsegmentval;
         if (((isJMPorCALL&0x1FF) == 1) && (!EXECSEGMENT_C(LOADEDDESCRIPTOR))) //JMP to a nonconforming segment?
         {
            if (GENERALSEGMENT_DPL(LOADEDDESCRIPTOR) != effectiveCPL()) //Different CPL?
            {
               goto throwdescsegmentval; //Throw error!
               return NULL; //We are a different privilege level, so don't load!                  
            }
         }
         else if (isJMPorCALL&0x1FF) //Call instruction (or JMP instruction to a conforming segment)
         {
            if (GENERALSEGMENT_DPL(LOADEDDESCRIPTOR) > effectiveCPL()) //We have a lower CPL?
            {
               goto throwdescsegmentval; //Throw error!
               return NULL; //We are a different privilege level, so don't load!
            }
         }
      }
   }

   switch (GENERALSEGMENT_TYPE(LOADEDDESCRIPTOR)) //We're a TSS? We're to perform a task switch!
   {
   case AVL_SYSTEM_BUSY_TSS16BIT:
   case AVL_SYSTEM_TSS16BIT: //TSS?
   case AVL_SYSTEM_BUSY_TSS32BIT:
   case AVL_SYSTEM_TSS32BIT: //TSS?
      is_TSS = (isGateDescriptor(&LOADEDDESCRIPTOR)==-1); //We're a TSS when a system segment!
      break;
   default:
      is_TSS = 0; //We're no TSS!
      break;
   }

   byte isnonconformingcode;
   isnonconformingcode = EXECSEGMENT_ISEXEC(LOADEDDESCRIPTOR) && (!EXECSEGMENT_C(LOADEDDESCRIPTOR)) && (getLoadedTYPE(&LOADEDDESCRIPTOR) == 1); //non-conforming code?
   //Now check for CPL,DPL&RPL! (chapter 6.3.2)
   if (
      (
      (!privilegedone && (getRPL(*segmentval)<effectiveCPL()) && (((isJMPorCALL&0x1FF)==4)||(isJMPorCALL&0x1FF)==3)) || //IRET/RETF to higher privilege level?
      ((GENERALSEGMENT_DPL(LOADEDDESCRIPTOR)>effectiveCPL()) && (EXECSEGMENT_ISEXEC(LOADEDDESCRIPTOR) && (getLoadedTYPE(&LOADEDDESCRIPTOR) == 1)) && (((isJMPorCALL&0x1FF)==2) || ((isJMPorCALL&0x1FF)==1))) || //CALL/JMP to a lower privilege?
      (!privilegedone && (MAX(effectiveCPL(),getRPL(*segmentval))>GENERALSEGMENT_DPL(LOADEDDESCRIPTOR)) && (((getLoadedTYPE(&LOADEDDESCRIPTOR)!=1) && (segment!=CPU_SEGMENT_SS)) || (isnonconformingcode && (segment!=CPU_SEGMENT_CS))) && ((isJMPorCALL&0x1FF)!=4) && ((isJMPorCALL&0x1FF)!=3)) || //We are a lower privilege level with either a data/system segment descriptor? Non-conforming code segments have different check for code segments only, but the same rule for data segments:
      (!privilegedone && (MAX((((isJMPorCALL&0x1FF)==4)||((isJMPorCALL&0x1FF)==3))?getRPL(*segmentval):effectiveCPL(),getRPL(*segmentval))<GENERALSEGMENT_DPL(LOADEDDESCRIPTOR)) && (EXECSEGMENT_ISEXEC(LOADEDDESCRIPTOR) && (EXECSEGMENT_C(LOADEDDESCRIPTOR)) && (getLoadedTYPE(&LOADEDDESCRIPTOR) == 1))) || //We must be at the same privilege level or higher compared to MAX(CPL,RPL) (or just RPL for RETF) for conforming code segment descriptors?
      (!privilegedone && ((((((isJMPorCALL&0x1FF)==4)||((isJMPorCALL&0x1FF)==3))?getRPL(*segmentval):effectiveCPL())!=GENERALSEGMENT_DPL(LOADEDDESCRIPTOR))) && isnonconformingcode && (segment==CPU_SEGMENT_CS)) || //We must be at the same privilege level compared to CPL (or RPL for RETF) for non-conforming code segment descriptors? Not for data segment selectors(the same as data segment descriptors).
      (!privilegedone && ((effectiveCPL()!=getRPL(*segmentval)) || (effectiveCPL()!=GENERALSEGMENT_DPL(LOADEDDESCRIPTOR))) && (segment==CPU_SEGMENT_SS)) //SS DPL must match CPL and RPL!
      )
      && (!(((isJMPorCALL&0x1FF)==3) && is_TSS)) //No privilege checking is done on IRET through TSS!
      && (!((isJMPorCALL&0x80)==0x80)) //Don't ignore privilege?
      )
   {
      //if ((segment == CPU_SEGMENT_SS) && (isJMPorCALL & 0x200) && ((isJMPorCALL & 0x8000) == 0)) goto throwSSoriginalval;
      //if ((segment == CPU_SEGMENT_SS) && (isJMPorCALL & 0x200) && ((isJMPorCALL & 0x8000) == 0)) goto throwSSoriginalval;
   throwdescoriginalval:
      if (isJMPorCALL & 0x200) //TSS is the cause?
      {
         THROWDESCTS(originalval, 1, (originalval & 4) ? EXCEPTION_TABLE_LDT : EXCEPTION_TABLE_GDT); //Throw error!
      }
      else //Plain #GP?
      {
         THROWDESCGP(originalval, ((isJMPorCALL & 0x400) >> 10), (originalval & 4) ? EXCEPTION_TABLE_LDT : EXCEPTION_TABLE_GDT); //Throw error!
      }
      return NULL; //Not present: limit exceeded!
      /*
   throwSSoriginalval:
      THROWDESCSS(originalval,((isJMPorCALL&0x400)>>10),(originalval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
      return NULL; //Not present: limit exceeded!
      */
   }

   if (is_TSS && (*segmentval & 4)) //TSS in LDT detected? That's not allowed!
   {
      goto throwdescoriginalval; //Throw error!
      return NULL; //Error out!
   }

   if ((segment==CPU_SEGMENT_CS) && is_TSS && ((isJMPorCALL&0x200)==0)) //Special stuff on CS, CPL, Task switch.
   {
      //Present is handled by the task switch mechanism, so don't check it here!

      //Execute a normal task switch!
      if (CPU_executionphase_starttaskswitch(segment,&LOADEDDESCRIPTOR,segmentval,*segmentval,isJMPorCALL,is_gated,-1)) //Switching to a certain task?
      {
         return NULL; //Error changing priviledges or anything else!
      }

      //We've properly switched to the destination task! Continue execution normally!
      return NULL; //Don't actually load CS with the descriptor: we've caused a task switch after all!
   }

   if ((segment == CPU_SEGMENT_CS) && (is_gated == 0) && (getLoadedTYPE(&LOADEDDESCRIPTOR)==1) && (((isJMPorCALL & 0x1FF) == 2)||((isJMPorCALL & 0x1FF) == 1))) //CALL/JMP to lower or different privilege?
   {
      if ((GENERALSEGMENT_DPL(LOADEDDESCRIPTOR) > effectiveCPL()) && EXECSEGMENT_C(LOADEDDESCRIPTOR)) //Conforming and lower privilege?
      {
         goto throwdescoriginalval; //Throw #GP error!      
      }
      if (((getRPL(*segmentval) > effectiveCPL()) || (GENERALSEGMENT_DPL(LOADEDDESCRIPTOR) != effectiveCPL())) && !EXECSEGMENT_C(LOADEDDESCRIPTOR)) //Non-conforming and different privilege or lowering privilege?
      {
         goto throwdescoriginalval; //Throw #GP error!      
      }
      //Non-conforming always must match CPL, so we don't handle it here(it's in the generic check)!
   }

   //Handle invalid types to load now!
   switch (getLoadedTYPE(&LOADEDDESCRIPTOR))
   {
   case 0: //Data descriptor?
      if ((segment==CPU_SEGMENT_CS) || (segment==CPU_SEGMENT_LDTR) || (segment==CPU_SEGMENT_TR)) //Data descriptor in invalid type?
      {
         goto throwdescsegmentval; //Throw #GP error!
         return NULL; //Not present: invalid descriptor type loaded!
      }
      if ((DATASEGMENT_W(LOADEDDESCRIPTOR) == 0) && (segment == CPU_SEGMENT_SS)) //Non-writable SS segment?
      {
         goto throwdescsegmentval; //Throw #GP error!
         return NULL; //Not present: invalid descriptor type loaded!
      }
      break;
   case 1: //Executable descriptor?
      if ((segment != CPU_SEGMENT_CS) && (EXECSEGMENT_R(LOADEDDESCRIPTOR) == 0)) //Executable non-readable in non-executable segment?
      {
         goto throwdescsegmentval; //Throw #GP error!
         return NULL; //Not present: invalid descriptor type loaded!
      }
      if (((segment == CPU_SEGMENT_LDTR) || (segment == CPU_SEGMENT_TR) || (segment == CPU_SEGMENT_SS))) //Executable segment in invalid register?
      {
         goto throwdescsegmentval; //Throw #GP error!
         return NULL; //Not present: invalid descriptor type loaded!
      }
      break;
   case 2: //System descriptor?
      if ((segment!=CPU_SEGMENT_LDTR) && (segment!=CPU_SEGMENT_TR)) //System descriptor in invalid register?
      {
         goto throwdescsegmentval; //Throw #GP error!
         return NULL; //Not present: invalid descriptor type loaded!
      }
      if ((segment == CPU_SEGMENT_LDTR) && (GENERALSEGMENT_TYPE(LOADEDDESCRIPTOR) != AVL_SYSTEM_LDT)) //Invalid LDT load?
      {
         goto throwdescsegmentval; //Throw #GP error!
         return NULL; //Not present: invalid descriptor type loaded!
      }
      if ((segment == CPU_SEGMENT_TR) && (is_TSS == 0)) //Non-TSS into task register?
      {
         goto throwdescsegmentval; //Throw #GP error!
         return NULL; //Not present: invalid descriptor type loaded!
      }
      break;
   default: //Unknown descriptor type? Count as invalid!
      goto throwdescsegmentval; //Throw #GP error!
      return NULL; //Not present: invalid descriptor type loaded!
      break;
   }

   //Make sure we're present last!
   if (GENERALSEGMENT_P(LOADEDDESCRIPTOR)==0) //Not present loaded into non-data NULL register?
   {
      if (segment==CPU_SEGMENT_SS) //Stack fault?
      {
         goto throwSSsegmentval;
      }
      else
      {
         THROWDESCNP(*segmentval,(isJMPorCALL&0x200)?1:((isJMPorCALL&0x400)>>10),(*segmentval&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
      }
      return NULL; //We're an invalid TSS to execute!
   }


   if ((segment == CPU_SEGMENT_CS) && (isGateDescriptor(&GATEDESCRIPTOR) == 1) && (is_gated)) //Gated CS?
   {
      switch (GENERALSEGMENT_TYPE(GATEDESCRIPTOR)) //What type of gate are we using?
      {
      case AVL_SYSTEM_CALLGATE16BIT: //16-bit call gate?
         callgatetype = 1; //16-bit call gate!
         break;
      case AVL_SYSTEM_CALLGATE32BIT: //32-bit call gate?
         callgatetype = 2; //32-bit call gate!
         break;
      default:
         callgatetype = 0; //No call gate!
         break;
      }
      if (callgatetype) //To process a call gate's parameters and offsets?
      {
         destEIP = (uint_32)GATEDESCRIPTOR.desc.callgate_base_low; //16-bit EIP!
         if (callgatetype == 2) //32-bit destination?
         {
            destEIP |= (((uint_32)GATEDESCRIPTOR.desc.callgate_base_mid)<<16); //Mid EIP!
            destEIP |= (((uint_32)GATEDESCRIPTOR.desc.callgate_base_high)<<24); //High EIP!
         }
         uint_32 argument; //Current argument to copy to the destination stack!
         word arguments;
         CPU[activeCPU].CallGateParamCount = 0; //Clear our stack to transfer!
         CPU[activeCPU].CallGateSize = (callgatetype==2)?1:0; //32-bit vs 16-bit call gate!

         if ((GENERALSEGMENT_DPL(LOADEDDESCRIPTOR)<effectiveCPL()) && (EXECSEGMENT_C(LOADEDDESCRIPTOR)==0) && ((isJMPorCALL&0x1FF)==2)) //Stack switch required (with CALL only)?
         {
            //Now, copy the stack arguments!

            *isdifferentCPL = 1; //We're a different level!
            arguments = CALLGATE_NUMARGUMENTS =  (GATEDESCRIPTOR.desc.ParamCnt&0x1F); //Amount of parameters!
            CPU[activeCPU].CallGateParamCount = 0; //Initialize the amount of arguments that we're storing!
            if (checkStackAccess(arguments,0,(callgatetype==2)?1:0)) return NULL; //Abort on stack fault!
            for (;arguments--;) //Copy as many arguments as needed!
            {
               if (callgatetype==2) //32-bit source?
               {
                  argument = MMU_rdw(CPU_SEGMENT_SS, REG_SS, REG_ESP&getstackaddrsizelimiter(), 0,!STACK_SEGMENT_DESCRIPTOR_B_BIT()); //POP 32-bit argument!
                  if (STACK_SEGMENT_DESCRIPTOR_B_BIT()) //32-bits?
                  {
                     REG_ESP += 4; //Increase!
                  }
                  else //16-bits?
                  {
                     REG_SP += 4; //Increase!
                  }
               }
               else //16-bit source?
               {
                  argument = MMU_rw(CPU_SEGMENT_SS, REG_SS, (REG_ESP&getstackaddrsizelimiter()), 0,!STACK_SEGMENT_DESCRIPTOR_B_BIT()); //POP 16-bit argument!
                  if (STACK_SEGMENT_DESCRIPTOR_B_BIT()) //32-bits?
                  {
                     REG_ESP += 2; //Increase!
                  }
                  else //16-bits?
                  {
                     REG_SP += 2; //Increase!
                  }
               }
               CPU[activeCPU].CallGateStack[CPU[activeCPU].CallGateParamCount++] = argument; //Add the argument to the call gate buffer to transfer to the new stack! Implement us as a LIFO for transfers!
            }
         }
         else
         {
            *isdifferentCPL = 2; //Indicate call gate determines operand size!
         }
      }
   }

   validLDTR:
   memcpy(dest,&LOADEDDESCRIPTOR,sizeof(LOADEDDESCRIPTOR)); //Give the loaded descriptor!

   return dest; //Give the segment descriptor read from memory!
}

word segmentWritten_tempSS;
uint_32 segmentWritten_tempESP;
word segmentWritten_tempSP;
extern word RETF_popbytes; //How many to pop?
byte is_stackswitching=0; //Are we busy stack switching?

byte RETF_checkSegmentRegisters[4] = {CPU_SEGMENT_ES,CPU_SEGMENT_FS,CPU_SEGMENT_GS,CPU_SEGMENT_DS}; //All segment registers to check for when returning to a lower privilege level!

word segmentWrittenVal, isJMPorCALLval;

byte segmentWritten(int segment, word value, word isJMPorCALL) //A segment register has been written to!
{
   byte RETF_segmentregister=0,RETF_whatsegment; //A segment register we're checking during a RETF instruction!
   byte oldCPL= getCPL();
   byte isDifferentCPL;
   byte isnonconformingcodeordata;
   sbyte loadresult;
   uint_32 tempesp;
   segmentWrittenVal = value; //What value is written!
   isJMPorCALLval = isJMPorCALL; //What type of write are we?
   if (getcpumode()==CPU_MODE_PROTECTED) //Protected mode, must not be real or V8086 mode, so update the segment descriptor cache!
   {
      isDifferentCPL = 0; //Default: same CPL!
      SEGMENT_DESCRIPTOR tempdescriptor;
      SEGMENT_DESCRIPTOR *descriptor = getsegment_seg(segment,&tempdescriptor,&value,isJMPorCALL,&isDifferentCPL); //Read the segment!
      uint_32 stackval;
      word stackval16; //16-bit stack value truncated!
      if (descriptor) //Loaded&valid?
      {
         if ((segment == CPU_SEGMENT_CS) && (((isJMPorCALL&0x1FF) == 2) || ((isJMPorCALL&0x1FF)==1))) //JMP(with call gate)/CALL needs pushed data on the stack?
         {
            if ((isDifferentCPL==1) && ((isJMPorCALL&0x1FF) == 2)) //Stack switch is required with CALL only?
            {
               //TSSSize = 0; //Default to 16-bit TSS!
               switch (GENERALSEGMENT_TYPE(CPU[activeCPU].SEG_DESCRIPTOR[CPU_SEGMENT_TR])) //What kind of TSS?
               {
               case AVL_SYSTEM_BUSY_TSS32BIT:
               case AVL_SYSTEM_TSS32BIT:
                  //TSSSize = 1; //32-bit TSS!
               case AVL_SYSTEM_BUSY_TSS16BIT:
               case AVL_SYSTEM_TSS16BIT:
                  if (switchStacks(GENERALSEGMENTPTR_DPL(descriptor)|((isJMPorCALL&0x400)>>8))) return 1; //Abort failing switching stacks!
                  
                  if (checkStackAccess(2,1,CPU[activeCPU].CallGateSize)) return 1; //Abort on error!

                  CPU_PUSH16(&CPU[activeCPU].oldSS,CPU[activeCPU].CallGateSize); //SS to return!

                  if (CPU[activeCPU].CallGateSize)
                  {
                     CPU_PUSH32(&CPU[activeCPU].oldESP);
                  }
                  else
                  {
                     word temp=(word)(CPU[activeCPU].oldESP&0xFFFF);
                     CPU_PUSH16(&temp,0);
                  }
                  
                  //Now, we've switched to the destination stack! Load all parameters onto the new stack!
                  if (checkStackAccess(CPU[activeCPU].CallGateParamCount,1,CPU[activeCPU].CallGateSize)) return 1; //Abort on error!
                  for (;CPU[activeCPU].CallGateParamCount;) //Process the CALL Gate Stack!
                  {
                     stackval = CPU[activeCPU].CallGateStack[--CPU[activeCPU].CallGateParamCount]; //Read the next value to store!
                     if (CPU[activeCPU].CallGateSize) //32-bit stack to push to?
                     {
                        CPU_PUSH32(&stackval); //Push the 32-bit stack value to the new stack!
                     }
                     else //16-bit?
                     {
                        stackval16 = (word)(stackval&0xFFFF); //Reduced data if needed!
                        CPU_PUSH16(&stackval16,0); //Push the 16-bit stack value to the new stack!
                     }
                  }
                  break;
               default:
                  break;
               }
            }
            else if (isDifferentCPL==0) //Unchanging CPL? Take call size from operand size!
            {
               CPU[activeCPU].CallGateSize = CPU_Operand_size[activeCPU]; //Use the call instruction size!
            }
            //Else, call by call gate size!
            
            if ((isJMPorCALL&0x1FF)==2) //CALL pushes return address!
            {
               if (checkStackAccess(2,1,CPU[activeCPU].CallGateSize)) return 1; //Abort on error!

               //Push the old address to the new stack!
               if (CPU[activeCPU].CallGateSize) //32-bit?
               {
                  CPU_PUSH16(&REG_CS,1);
                  CPU_PUSH32(&REG_EIP);
               }
               else //16-bit?
               {
                  CPU_PUSH16(&REG_CS,0);
                  CPU_PUSH16(&REG_IP,0);
               }
            }

            /*if ((EXECSEGMENTPTR_C(descriptor)==0) && (isDifferentCPL==1)) //Non-Conforming segment, call gate and more privilege?
            {
               CPU[activeCPU].CPL = GENERALSEGMENTPTR_DPL(descriptor); //CPL = DPL!
            }*/
            setRPL(value,getCPL()); //RPL of CS always becomes CPL!

            if (isDifferentCPL==1) //Different CPL?
            {
               hascallinterrupttaken_type = CALLGATE_NUMARGUMENTS?CALLGATE_DIFFERENTLEVEL_XPARAMETERS:CALLGATE_DIFFERENTLEVEL_NOPARAMETERS; //INT gate type taken. Low 4 bits are the type. High 2 bits are privilege level/task gate flag. Left at 0xFF when nothing is used(unknown case?)
            }
            else //Same CPL call gate?
            {
               hascallinterrupttaken_type = CALLGATE_SAMELEVEL; //Same level call gate!
            }
         }
         else if ((segment == CPU_SEGMENT_CS) && ((isJMPorCALL&0x1FF) == 4)) //RETF needs popped data on the stack?
         {
            if (is_stackswitching == 0) //We're ready to process?
            {
               if (STACK_SEGMENT_DESCRIPTOR_B_BIT())
               {
                  REG_ESP += RETF_popbytes; //Process ESP!
               }
               else
               {
                  REG_SP += RETF_popbytes; //Process SP!
               }
               if (oldCPL < getRPL(value)) //Lowering privilege?
               {
                  if (checkStackAccess(2, 0, CPU_Operand_size[activeCPU])) return 1; //Stack fault?
               }
            }

            if (oldCPL<getRPL(value)) //CPL changed or still busy for this stage?
            {
               //Now, return to the old prvilege level!
               hascallinterrupttaken_type = RET_DIFFERENTLEVEL; //INT gate type taken. Low 4 bits are the type. High 2 bits are privilege level/task
               if (CPU_Operand_size[activeCPU])
               {
                  if (CPU80386_internal_POPdw(6, &segmentWritten_tempESP))
                  {
                     //CPU[activeCPU].CPL = oldCPL; //Restore CPL for continuing!
                     is_stackswitching = 1; //We're stack switching!
                     return 1; //POP ESP!
                  }
               }
               else
               {
                  if (CPU8086_internal_POPw(6, &segmentWritten_tempSP, 0))
                  {
                     //CPU[activeCPU].CPL = oldCPL; //Restore CPL for continuing!
                     is_stackswitching = 1; //We're stack switching!
                     return 1; //POP SP!
                  }
               }
               if (CPU8086_internal_POPw(8, &segmentWritten_tempSS, CPU_Operand_size[activeCPU]))
               {
                  //CPU[activeCPU].CPL = oldCPL; //Restore CPL for continuing!
                  is_stackswitching = 1; //We're stack switching!
                  return 1; //POPped?
               }
               is_stackswitching = 0; //We've finished stack switching!
               //Privilege change!
               if (segmentWritten(CPU_SEGMENT_SS,segmentWritten_tempSS,(getRPL(value)<<13)|0x1000)) return 1; //Back to our calling stack!
               if (CPU_Operand_size[activeCPU])
               {
                  REG_ESP = segmentWritten_tempESP; //POP ESP!
               }
               else
               {
                  REG_ESP = (uint_32)segmentWritten_tempSP; //POP SP!
               }
               RETF_segmentregister = 1; //We're checking the segments for privilege changes to be invalidated!
            }
            else if (oldCPL > getRPL(value)) //CPL raised during RETF?
            {
               THROWDESCGP(value, (isJMPorCALL&0x200)?1:(((isJMPorCALL&0x400)>>10)), (value & 4) ? EXCEPTION_TABLE_LDT : EXCEPTION_TABLE_GDT); //Raising CPL using RETF isn't allowed!
               return 1; //Abort on fault!
            }
            else //Same privilege? (E)SP on the destination stack is already processed, don't process again!
            {
               RETF_popbytes = 0; //Nothing to pop anymore!
            }
         }
         else if ((segment==CPU_SEGMENT_CS) && ((isJMPorCALL&0x1FF)==3)) //IRET might need extra data popped?
         {
            if (getRPL(value)>oldCPL) //Stack needs to be restored when returning to outer privilege level!
            {
               if (checkStackAccess(2,0,CPU_Operand_size[activeCPU])) return 1; //First level IRET data?
               if (CPU_Operand_size[activeCPU])
               {
                  tempesp = CPU_POP32();
               }
               else
               {
                  tempesp = CPU_POP16(CPU_Operand_size[activeCPU]);
               }

               segmentWritten_tempSS = CPU_POP16(CPU_Operand_size[activeCPU]);

               if (segmentWritten(CPU_SEGMENT_SS,segmentWritten_tempSS,(getRPL(value)<<13)|0x1000)) return 1; //Back to our calling stack!
               REG_ESP = tempesp;

               RETF_segmentregister = 1; //We're checking the segments for privilege changes to be invalidated!
            }
            else if (oldCPL > getRPL(value)) //CPL raised during IRET?
            {
               THROWDESCGP(value, (isJMPorCALL&0x200)?1:((isJMPorCALL&0x400)>>10), (value & 4) ? EXCEPTION_TABLE_LDT : EXCEPTION_TABLE_GDT); //Raising CPL using RETF isn't allowed!
               return 1; //Abort!
            }
         }

         if (segment==CPU_SEGMENT_TR) //Loading the Task Register? We're to mask us as busy!
         {
            if ((isJMPorCALL&0x1FF)==0) //Not a JMP or CALL itself, or a task switch, so just a plain load using LTR?
            {
               SEGMENT_DESCRIPTOR savedescriptor;
               switch (GENERALSEGMENT_TYPE(tempdescriptor)) //What kind of TSS?
               {
               case AVL_SYSTEM_BUSY_TSS32BIT:
               case AVL_SYSTEM_BUSY_TSS16BIT:
                  if ((isJMPorCALL & 0x800) == 0) //Needs to be non-busy?
                  {
                     THROWDESCGP(value, (isJMPorCALL & 0x200) ? 1 : (((isJMPorCALL & 0x400) >> 10)), (value & 4) ? EXCEPTION_TABLE_LDT : EXCEPTION_TABLE_GDT); //We cannot load a busy TSS!
                     return 1; //Abort on fault!
                  }
                  break;
               case AVL_SYSTEM_TSS32BIT:
               case AVL_SYSTEM_TSS16BIT:
                  if ((isJMPorCALL & 0x800)) //Needs to be busy?
                  {
                     THROWDESCGP(value, (isJMPorCALL & 0x200) ? 1 : (((isJMPorCALL & 0x400) >> 10)), (value & 4) ? EXCEPTION_TABLE_LDT : EXCEPTION_TABLE_GDT); //We cannot load a busy TSS!
                     return 1; //Abort on fault!
                  }

                  tempdescriptor.desc.AccessRights |= 2; //Mark not idle in the RAM descriptor!
                  savedescriptor.desc.DATA64 = tempdescriptor.desc.DATA64; //Copy the resulting descriptor contents to our buffer for writing to RAM!
                  if (SAVEDESCRIPTOR(segment,value,&savedescriptor,isJMPorCALL)<=0) //Save it back to RAM failed?
                  {
                     return 1; //Abort on fault!
                  }
                  break;
               default: //Invalid segment descriptor to load into the TR register?
                  THROWDESCGP(value,(isJMPorCALL&0x200)?1:((isJMPorCALL&0x400)>>10),(value&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //We cannot load a busy TSS!
                  return 1; //Abort on fault!
                  break; //Ignore!
               }
            }
         }
         //Now, load the new descriptor and address for CS if needed(with secondary effects)!
         if ((CPU[activeCPU].have_oldSegReg&(1 << segment)) == 0) //Backup not loaded yet?
         {
            memcpy(&CPU[activeCPU].SEG_DESCRIPTORbackup[segment], &CPU[activeCPU].SEG_DESCRIPTOR[segment], sizeof(CPU[activeCPU].SEG_DESCRIPTORbackup[0])); //Restore the descriptor!
            CPU[activeCPU].oldSegReg[segment] = *CPU[activeCPU].SEGMENT_REGISTERS[segment]; //Backup the register too!
            CPU[activeCPU].have_oldSegReg |= (1 << segment); //Loaded!
         }
         memcpy(&CPU[activeCPU].SEG_DESCRIPTOR[segment],descriptor,sizeof(CPU[activeCPU].SEG_DESCRIPTOR[segment])); //Load the segment descriptor into the cache!
         //if (memprotect(CPU[activeCPU].SEGMENT_REGISTERS[segment],2,"CPU_REGISTERS")) //Valid segment register?
         {
            *CPU[activeCPU].SEGMENT_REGISTERS[segment] = value; //Set the segment register to the allowed value!
         }

         if ((loadresult = touchSegment(segment,value,descriptor,isJMPorCALL))<=0) //Errored out during touching?
         {
            if (loadresult == 0) //Not already faulted?
            {
               if (isJMPorCALL&0x200) //TSS is the cause?
               {
                  THROWDESCTS(value,1,(value&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!         
               }
               else //Plain #GP?
               {
                  THROWDESCGP(value,((isJMPorCALL&0x400)>>10),(value&4)?EXCEPTION_TABLE_LDT:EXCEPTION_TABLE_GDT); //Throw error!
               }
            }
            return 1; //Abort on fault!
         }

         if (segment == CPU_SEGMENT_CS) //CS register?
         {
            REG_EIP = destEIP; //The current OPCode: just jump to the address specified by the descriptor OR command!
            if (((isJMPorCALL & 0x1FF) == 4) || ((isJMPorCALL & 0x1FF) == 3)) //IRET/RETF required limit check!
            {
               if (CPU_MMU_checkrights(CPU_SEGMENT_CS, REG_CS, REG_EIP, 3, &CPU[activeCPU].SEG_DESCRIPTOR[CPU_SEGMENT_CS], 2, CPU_Operand_size[activeCPU])) //Limit broken or protection fault?
               {
                  THROWDESCGP(0, 0, 0); //#GP(0) when out of limit range!
                  return 1; //Abort on fault!
               }
            }
         }
         else if (segment == CPU_SEGMENT_SS) //SS? We're also updating the CPL!
         {
            updateCPL(); //Update the CPL according to the mode!
         }

         if (RETF_segmentregister) //Are we to check the segment registers for validity during a RETF?
         {
            for (RETF_segmentregister = 0; RETF_segmentregister < NUMITEMS(RETF_checkSegmentRegisters); ++RETF_segmentregister) //Process all we need to check!
            {
               RETF_whatsegment = RETF_checkSegmentRegisters[RETF_segmentregister]; //What register to check?
               word descriptor_index;
               descriptor_index = getDescriptorIndex(*CPU[activeCPU].SEGMENT_REGISTERS[RETF_whatsegment]); //What descriptor index?
               if (descriptor_index) //Valid index(Non-NULL)?
               {
                  if ((word)(descriptor_index | 0x7) > ((*CPU[activeCPU].SEGMENT_REGISTERS[RETF_whatsegment] & 4) ? CPU[activeCPU].SEG_DESCRIPTOR[CPU_SEGMENT_LDTR].PRECALCS.limit : CPU[activeCPU].registers->GDTR.limit)) //LDT/GDT limit exceeded?
                  {
                  invalidRETFsegment:
                     if ((CPU[activeCPU].have_oldSegReg&(1 << RETF_whatsegment)) == 0) //Backup not loaded yet?
                     {
                        memcpy(&CPU[activeCPU].SEG_DESCRIPTORbackup[RETF_whatsegment], &CPU[activeCPU].SEG_DESCRIPTOR[RETF_whatsegment], sizeof(CPU[activeCPU].SEG_DESCRIPTORbackup[0])); //Restore the descriptor!
                        CPU[activeCPU].oldSegReg[RETF_whatsegment] = *CPU[activeCPU].SEGMENT_REGISTERS[RETF_whatsegment]; //Backup the register too!
                        CPU[activeCPU].have_oldSegReg |= (1 << RETF_whatsegment); //Loaded!
                     }
                     //Selector and Access rights are zeroed!
                     *CPU[activeCPU].SEGMENT_REGISTERS[RETF_whatsegment] = 0; //Zero the register!
                     if ((isJMPorCALL&0x1FF) == 3) //IRET?
                     {
                        CPU[activeCPU].SEG_DESCRIPTOR[RETF_whatsegment].desc.AccessRights &= 0x7F; //Clear the valid flag only with IRET!
                     }
                     else //RETF?
                     {
                        CPU[activeCPU].SEG_DESCRIPTOR[RETF_whatsegment].desc.AccessRights = 0; //Invalid!
                     }
                     CPU_calcSegmentPrecalcs(&CPU[activeCPU].SEG_DESCRIPTOR[RETF_whatsegment]); //Update the precalcs for said access rights!
                     continue; //Next register!
                  }
               }
               if (GENERALSEGMENT_P(CPU[activeCPU].SEG_DESCRIPTOR[RETF_whatsegment])==0) //Not present?
               {
                  goto invalidRETFsegment; //Next register!
               }
               if (GENERALSEGMENT_S(CPU[activeCPU].SEG_DESCRIPTOR[RETF_whatsegment])==0) //Not data/readable code segment?
               {
                  goto invalidRETFsegment; //Next register!
               }
               //We're either data or code!
               isnonconformingcodeordata = 0; //Default: neither!
               if (EXECSEGMENT_ISEXEC(CPU[activeCPU].SEG_DESCRIPTOR[RETF_whatsegment])) //Code?
               {
                  if (!EXECSEGMENT_C(CPU[activeCPU].SEG_DESCRIPTOR[RETF_whatsegment])) //Nonconforming? Invalid!
                  {
                     isnonconformingcodeordata = 1; //Next register!
                  }
                  if (!EXECSEGMENT_R(CPU[activeCPU].SEG_DESCRIPTOR[RETF_whatsegment])) //Not readable? Invalid!
                  {
                     goto invalidRETFsegment; //Next register!
                  }
               }
               else isnonconformingcodeordata = 1; //Data!
               //We're either data or readable code!
               if (isnonconformingcodeordata && (GENERALSEGMENT_DPL(CPU[activeCPU].SEG_DESCRIPTOR[RETF_whatsegment])<MAX(getCPL(),getRPL(*CPU[activeCPU].SEGMENT_REGISTERS[RETF_whatsegment])))) //Not privileged enough to handle said segment descriptor?
               {
                  goto invalidRETFsegment; //Next register!
               }
            }
         }
         if (segment == CPU_SEGMENT_CS)
         {
            if (CPU_condflushPIQ(-1)) return 1; //We're jumping to another address!
         }
      }
      else //A fault has been raised? Abort!
      {
         if (segment == CPU_SEGMENT_CS)
         {
            CPU_flushPIQ(-1); //We're jumping to another address!
         }
         return 1; //Abort on fault!
      }
   }
   else //Real mode has no protection?
   {
      if ((isJMPorCALL&0x1FF) == 2) //CALL needs pushed data?
      {
         if ((CPU_Operand_size[activeCPU]) && (EMULATED_CPU>=CPU_80386)) //32-bit?
         {
            if (CPU[activeCPU].internalinstructionstep==0) if (checkStackAccess(2, 1, 1)) return 1; //We're trying to push on the stack!
            uint_32 pushingval;
            pushingval = REG_CS; //What to push!
            if (CPU80386_internal_PUSHdw(0,&pushingval)) return 1;
            if (CPU80386_internal_PUSHdw(2,&REG_EIP)) return 1;
         }
         else //16-bit?
         {
            if (CPU[activeCPU].internalinstructionstep==0) if(checkStackAccess(2, 1, 0)) return 1; //We're trying to push on the stack!
            if (CPU8086_internal_PUSHw(0,&REG_CS,0)) return 1;
            if (CPU8086_internal_PUSHw(2,&REG_IP,0)) return 1;
         }
      }

      if ((CPU[activeCPU].have_oldSegReg&(1 << segment)) == 0) //Backup not loaded yet?
      {
         memcpy(&CPU[activeCPU].SEG_DESCRIPTORbackup[segment], &CPU[activeCPU].SEG_DESCRIPTOR[segment], sizeof(CPU[activeCPU].SEG_DESCRIPTORbackup[0])); //Restore the descriptor!
         CPU[activeCPU].oldSegReg[segment] = *CPU[activeCPU].SEGMENT_REGISTERS[segment]; //Backup the register too!
         CPU[activeCPU].have_oldSegReg |= (1 << segment); //Loaded!
      }

      //if (memprotect(CPU[activeCPU].SEGMENT_REGISTERS[segment],2,"CPU_REGISTERS")) //Valid segment register?
      {
         *CPU[activeCPU].SEGMENT_REGISTERS[segment] = value; //Just set the segment, don't load descriptor!
         //Load the correct base data for our loading!
         CPU[activeCPU].SEG_DESCRIPTOR[segment].desc.base_low = (word)(((uint_32)value<<4)&0xFFFF); //Low base!
         CPU[activeCPU].SEG_DESCRIPTOR[segment].desc.base_mid = ((((uint_32)value << 4) & 0xFF0000)>>16); //Mid base!
         CPU[activeCPU].SEG_DESCRIPTOR[segment].desc.base_high = ((((uint_32)value << 4) & 0xFF000000)>>24); //High base!
         //This also maps the resulting segment in low memory (20-bit address space) in real mode, thus CS is pulled low as well!
         //Real mode affects only CS like Virtual 8086 mode(reloading all base/limit values). Other segments are unmodified.
         //Virtual 8086 mode also loads the rights etc.? This is to prevent Virtual 8086 tasks having leftover data in their descriptors, causing faults!
         if ((segment==CPU_SEGMENT_CS) || (getcpumode()==CPU_MODE_8086)) //Only done for the CS segment in real mode as well as all registers in 8086 mode?
         {
            CPU[activeCPU].SEG_DESCRIPTOR[segment].desc.AccessRights = 0x93; //Compatible rights!
            CPU[activeCPU].SEG_DESCRIPTOR[segment].desc.limit_low = 0xFFFF;
            CPU[activeCPU].SEG_DESCRIPTOR[segment].desc.noncallgate_info = 0x00; //Not used!
         }
      }
      if (segment==CPU_SEGMENT_CS) //CS segment? Reload access rights in real mode on first write access!
      {
         CPU[activeCPU].SEG_DESCRIPTOR[CPU_SEGMENT_CS].desc.AccessRights = 0x93; //Load default access rights!
         CPU_calcSegmentPrecalcs(&CPU[activeCPU].SEG_DESCRIPTOR[segment]); //Calculate any precalcs for the segment descriptor(do it here since we don't load descriptors externally)!
         REG_EIP = destEIP; //... The current OPCode: just jump to the address!
      }
      else if (segment == CPU_SEGMENT_SS) //SS? We're also updating the CPL!
      {
         updateCPL(); //Update the CPL according to the mode!
         CPU_calcSegmentPrecalcs(&CPU[activeCPU].SEG_DESCRIPTOR[segment]); //Calculate any precalcs for the segment descriptor(do it here since we don't load descriptors externally)!
      }
      else
      {
         CPU_calcSegmentPrecalcs(&CPU[activeCPU].SEG_DESCRIPTOR[segment]); //Calculate any precalcs for the segment descriptor(do it here since we don't load descriptors externally)!
      }
   }
   //Real mode doesn't use the descriptors?
   if (segment == CPU_SEGMENT_CS)
   {
      if (CPU_condflushPIQ(-1)) return 1; //We're jumping to another address!
   }
   return 0; //No fault raised&continue!
}


Is that correct behaviour? segmentWritten is used in all cases but interrupt handling.
superfury
l33t
 
Posts: 3288
Joined: 2014-3-08 @ 11:25
Location: Netherlands

Re: Finding out what's crashing Windows 95?

Postby superfury » 2019-11-13 @ 08:57

The crash happens at 117:6622. Anyone knows what vxd LDT 110h is?
superfury
l33t
 
Posts: 3288
Joined: 2014-3-08 @ 11:25
Location: Netherlands

Re: Finding out what's crashing Windows 95?

Postby superfury » 2019-11-14 @ 22:38

Hmmm... Having fixed the 16-bit push/pop instructions to use 16-bit operands, the crash at 117:6522 is now due to a RETF to ecc4:bffbb368.

Hmmm... Didn't I see that ecc4 segment before at the Windows 95 setup.exe loading from the CD-ROM before, also faulting the same way( just before or after the unpackimg of the installer cabinets)?

Edit: Some identifying information:
TR:18:C000AEBC
CR3:2e9000
Of course, the TR 'offset' is the TR base as usual.
superfury
l33t
 
Posts: 3288
Joined: 2014-3-08 @ 11:25
Location: Netherlands

Re: Finding out what's crashing Windows 95?

Postby superfury » 2019-11-14 @ 23:03

It seems that information was good enough of a filter to probably find the stuff leading to the crash? It's pretty 'small': only 64MB large. But hopefully it can identify the problem(and should be able to upload it here):
debugger_segment117_WIN95Acrash.7z
Windows 95A crashing at 117:6522
(1.59 MiB) Not downloaded yet


Edit: The cause seems to somehow be immediately before that, popping something into ESP+08?

Code: Select all
   RealRAM(p):000edcc6=d7(×); RAM(p):0014dcc6=d7(×); Physical(p):0014dcc6=d7(×); Paged(p):0000ecc6=d7(×); Normal(p):00006526=d7(×); RealRAM(p):000edcc7=2b(+); RAM(p):0014dcc7=2b(+); Physical(p):0014dcc7=2b(+); Paged(p):0000ecc7=2b(+); Normal(p):00006527=2b(+); RealRAM(p):000edcc8=e6(æ); RAM(p):0014dcc8=e6(æ); Physical(p):0014dcc8=e6(æ); Paged(p):0000ecc8=e6(æ); Normal(p):00006528=e6(æ); RealRAM(p):000edcc9=66(f); RAM(p):0014dcc9=66(f); Physical(p):0014dcc9=66(f); Paged(p):0000ecc9=66(f); Normal(p):00006529=66(f); RealRAM(p):000edcca=16(); RAM(p):0014dcca=16(); Physical(p):0014dcca=16(); Paged(p):0000ecca=16(); Normal(p):0000652a=16(); RealRAM(p):000edccb=66(f); RAM(p):0014dccb=66(f); Physical(p):0014dccb=66(f); Paged(p):0000eccb=66(f); Normal(p):0000652b=66(f)
0117:0000651c 67 66 8F 44 24 08 pop dword ss:[esp+08]   RealRAM(r):00b41208=c4(Ä); RAM(r):00ba1208=c4(Ä); Physical(r):00ba1208=c4(Ä); Paged(r):0001a208=c4(Ä); RealRAM(r):00b41209=ec(ì); RAM(r):00ba1209=ec(ì); Physical(r):00ba1209=ec(ì); Paged(r):0001a209=ec(ì); RealRAM(r):00b4120a=00( ); RAM(r):00ba120a=00( ); Physical(r):00ba120a=00( ); Paged(r):0001a20a=00( ); RealRAM(r):00b4120b=00( ); RAM(r):00ba120b=00( ); Physical(r):00ba120b=00( ); Paged(r):0001a20b=00( ); Paged(w):0001a210=c4(Ä); Physical(w):00ba1210=c4(Ä); RAM(w):00ba1210=c4(Ä); RealRAM(w):00b41210=c4(Ä); Paged(w):0001a211=ec(ì); Physical(w):00ba1211=ec(ì); RAM(w):00ba1211=ec(ì); RealRAM(w):00b41211=ec(ì); Paged(w):0001a212=00( ); Physical(w):00ba1212=00( ); RAM(w):00ba1212=00( ); RealRAM(w):00b41212=00( ); Paged(w):0001a213=00( ); Physical(w):00ba1213=00( ); RAM(w):00ba1213=00( ); RealRAM(w):00b41213=00( )
Registers:
EAX: 0000a286 EBX: 01176e77 ECX: 00000137 EDX: 00090001
ESP: 0001a208 EBP: 00001fe4 ESI: 00018370 EDI: 00000097
CS: 0117 DS: 013f ES: 013f FS: 0167 GS: 0000 SS: 013f TR: 0018 LDTR: 00b8
EIP: 0000651c EFLAGS: 00000246
CR0: 80000011 CR1: 00000000 CR2: bffbc01a CR3: 002e9000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000c003765001f7 IDTR: 0000800ac00002ff
FLAGSINFO: 00000000000000vr0n00odItsZ0a0P1c
   RealRAM(p):000edccc=68(h); RAM(p):0014dccc=68(h); Physical(p):0014dccc=68(h); Paged(p):0000eccc=68(h); Normal(p):0000652c=68(h); RealRAM(p):000edccd=ff(ÿ); RAM(p):0014dccd=ff(ÿ); Physical(p):0014dccd=ff(ÿ); Paged(p):0000eccd=ff(ÿ); Normal(p):0000652d=ff(ÿ); RealRAM(p):000edcce=ff(ÿ); RAM(p):0014dcce=ff(ÿ); Physical(p):0014dcce=ff(ÿ); Paged(p):0000ecce=ff(ÿ); Normal(p):0000652e=ff(ÿ); RealRAM(p):000edccf=53(S); RAM(p):0014dccf=53(S); Physical(p):0014dccf=53(S); Paged(p):0000eccf=53(S); Normal(p):0000652f=53(S); RealRAM(p):000edcd0=66(f); RAM(p):0014dcd0=66(f); Physical(p):0014dcd0=66(f); Paged(p):0000ecd0=66(f); Normal(p):00006530=66(f); RealRAM(p):000edcd1=68(h); RAM(p):0014dcd1=68(h); Physical(p):0014dcd1=68(h); Paged(p):0000ecd1=68(h); Normal(p):00006531=68(h)
00:16:12:06.07008: #GP fault(0000ECC4)!
MMU: Reading from real(r): 001d2068=b0 (°)
Reading from RAM(r): 00232068=b0 (°)
Reading from physical memory(r): 00232068=b0 (°)
Reading from paged memory(r): 800ac068=b0 (°)
MMU: Reading from real(r): 001d2069=12 ()
Reading from RAM(r): 00232069=12 ()
Reading from physical memory(r): 00232069=12 ()
Reading from paged memory(r): 800ac069=12 ()
MMU: Reading from real(r): 001d206a=28 (()
Reading from RAM(r): 0023206a=28 (()
Reading from physical memory(r): 0023206a=28 (()
Reading from paged memory(r): 800ac06a=28 (()
MMU: Reading from real(r): 001d206b=00 ( )
Reading from RAM(r): 0023206b=00 ( )
Reading from physical memory(r): 0023206b=00 ( )
Reading from paged memory(r): 800ac06b=00 ( )
MMU: Reading from real(r): 001d206c=00 ( )
Reading from RAM(r): 0023206c=00 ( )
Reading from physical memory(r): 0023206c=00 ( )
Reading from paged memory(r): 800ac06c=00 ( )
MMU: Reading from real(r): 001d206d=8e (Ž)
Reading from RAM(r): 0023206d=8e (Ž)
Reading from physical memory(r): 0023206d=8e (Ž)
Reading from paged memory(r): 800ac06d=8e (Ž)
MMU: Reading from real(r): 001d206e=00 ( )
Reading from RAM(r): 0023206e=00 ( )
Reading from physical memory(r): 0023206e=00 ( )
Reading from paged memory(r): 800ac06e=00 ( )
MMU: Reading from real(r): 001d206f=c0 (À)
Reading from RAM(r): 0023206f=c0 (À)
Reading from physical memory(r): 0023206f=c0 (À)
Reading from paged memory(r): 800ac06f=c0 (À)
MMU: Reading from real(r): 00284678=ff (ÿ)
Reading from RAM(r): 002e4678=ff (ÿ)
Reading from physical memory(r): 002e4678=ff (ÿ)
Reading from paged memory(r): c0037678=ff (ÿ)
MMU: Reading from real(r): 00284679=ff (ÿ)
Reading from RAM(r): 002e4679=ff (ÿ)
Reading from physical memory(r): 002e4679=ff (ÿ)
Reading from paged memory(r): c0037679=ff (ÿ)
MMU: Reading from real(r): 0028467a=00 ( )
Reading from RAM(r): 002e467a=00 ( )
Reading from physical memory(r): 002e467a=00 ( )
Reading from paged memory(r): c003767a=00 ( )
MMU: Reading from real(r): 0028467b=00 ( )
Reading from RAM(r): 002e467b=00 ( )
Reading from physical memory(r): 002e467b=00 ( )
Reading from paged memory(r): c003767b=00 ( )
MMU: Reading from real(r): 0028467c=00 ( )
Reading from RAM(r): 002e467c=00 ( )
Reading from physical memory(r): 002e467c=00 ( )
Reading from paged memory(r): c003767c=00 ( )
MMU: Reading from real(r): 0028467d=9b (›)
Reading from RAM(r): 002e467d=9b (›)
Reading from physical memory(r): 002e467d=9b (›)
Reading from paged memory(r): c003767d=9b (›)
MMU: Reading from real(r): 0028467e=cf (Ï)
Reading from RAM(r): 002e467e=cf (Ï)
Reading from physical memory(r): 002e467e=cf (Ï)
Reading from paged memory(r): c003767e=cf (Ï)
MMU: Reading from real(r): 0028467f=00 ( )
Reading from RAM(r): 002e467f=00 ( )
Reading from physical memory(r): 002e467f=00 ( )
Reading from paged memory(r): c003767f=00 ( )
MMU: Reading from real(r): 00284680=ff (ÿ)
Reading from RAM(r): 002e4680=ff (ÿ)
Reading from physical memory(r): 002e4680=ff (ÿ)
Reading from paged memory(r): c0037680=ff (ÿ)
MMU: Reading from real(r): 00284681=ff (ÿ)
Reading from RAM(r): 002e4681=ff (ÿ)
Reading from physical memory(r): 002e4681=ff (ÿ)
Reading from paged memory(r): c0037681=ff (ÿ)
MMU: Reading from real(r): 00284682=00 ( )
Reading from RAM(r): 002e4682=00 ( )
Reading from physical memory(r): 002e4682=00 ( )
Reading from paged memory(r): c0037682=00 ( )
MMU: Reading from real(r): 00284683=00 ( )
Reading from RAM(r): 002e4683=00 ( )
Reading from physical memory(r): 002e4683=00 ( )
Reading from paged memory(r): c0037683=00 ( )
MMU: Reading from real(r): 00284684=00 ( )
Reading from RAM(r): 002e4684=00 ( )
Reading from physical memory(r): 002e4684=00 ( )
Reading from paged memory(r): c0037684=00 ( )
MMU: Reading from real(r): 00284685=93 (“)
Reading from RAM(r): 002e4685=93 (“)
Reading from physical memory(r): 002e4685=93 (“)
Reading from paged memory(r): c0037685=93 (“)
MMU: Reading from real(r): 00284686=cf (Ï)
Reading from RAM(r): 002e4686=cf (Ï)
Reading from physical memory(r): 002e4686=cf (Ï)
Reading from paged memory(r): c0037686=cf (Ï)
MMU: Reading from real(r): 00284687=00 ( )
Reading from RAM(r): 002e4687=00 ( )
Reading from physical memory(r): 002e4687=00 ( )
Reading from paged memory(r): c0037687=00 ( )
0117:00006522 66 CB retfd   RealRAM(r):00b4120c=68(h); RAM(r):00ba120c=68(h); Physical(r):00ba120c=68(h); Paged(r):0001a20c=68(h); RealRAM(r):00b4120d=b3(³); RAM(r):00ba120d=b3(³); Physical(r):00ba120d=b3(³); Paged(r):0001a20d=b3(³); RealRAM(r):00b4120e=fb(û); RAM(r):00ba120e=fb(û); Physical(r):00ba120e=fb(û); Paged(r):0001a20e=fb(û); RealRAM(r):00b4120f=bf(¿); RAM(r):00ba120f=bf(¿); Physical(r):00ba120f=bf(¿); Paged(r):0001a20f=bf(¿); RealRAM(r):00b41210=c4(Ä); RAM(r):00ba1210=c4(Ä); Physical(r):00ba1210=c4(Ä); Paged(r):0001a210=c4(Ä); RealRAM(r):00b41211=ec(ì); RAM(r):00ba1211=ec(ì); Physical(r):00ba1211=ec(ì); Paged(r):0001a211=ec(ì); RealRAM(r):00289803=00( ); RAM(r):002e9803=00( ); Physical(r):002e9803=00( ); RealRAM(r):00289802=30(0); RAM(r):002e9802=30(0); Physical(r):002e9802=30(0); RealRAM(r):00289801=72(r); RAM(r):002e9801=72(r); Physical(r):002e9801=72(r); RealRAM(r):00289800=67(g); RAM(r):002e9800=67(g); Physical(r):002e9800=67(g); RealRAM(r):002a72b3=00( ); RAM(r):003072b3=00( ); Physical(r):003072b3=00( ); RealRAM(r):002a72b2=23(#); RAM(r):003072b2=23(#); Physical(r):003072b2=23(#); RealRAM(r):002a72b1=22("); RAM(r):003072b1=22("); Physical(r):003072b1=22("); RealRAM(r):002a72b0=67(g); RAM(r):003072b0=67(g); Physical(r):003072b0=67(g); RealRAM(r):001c4ec0=a8(¨); RAM(r):00224ec0=a8(¨); Physical(r):00224ec0=a8(¨); Paged(r):c000aec0=a8(¨); Normal(r):00000004=a8(¨); RealRAM(r):001c4ec1=1f(); RAM(r):00224ec1=1f(); Physical(r):00224ec1=1f(); Paged(r):c000aec1=1f(); Normal(r):00000005=1f(); RealRAM(r):001c4ec2=3a(:); RAM(r):00224ec2=3a(:); Physical(r):00224ec2=3a(:); Paged(r):c000aec2=3a(:); Normal(r):00000006=3a(:); RealRAM(r):001c4ec3=c1(Á); RAM(r):00224ec3=c1(Á); Physical(r):00224ec3=c1(Á); Paged(r):c000aec3=c1(Á); Normal(r):00000007=c1(Á); RealRAM(r):001c4ec4=30(0); RAM(r):00224ec4=30(0); Physical(r):00224ec4=30(0); Paged(r):c000aec4=30(0); Normal(r):00000008=30(0); RealRAM(r):001c4ec5=00( ); RAM(r):00224ec5=00( ); Physical(r):00224ec5=00( ); Paged(r):c000aec5=00( ); Normal(r):00000009=00( ); Normal(w):c13a1fa4=3f(?); Paged(w):c13a1fa4=3f(?); Physical(w):0035bfa4=3f(?); RAM(w):0035bfa4=3f(?); RealRAM(w):002fbfa4=3f(?); Normal(w):c13a1fa5=01(); Paged(w):c13a1fa5=01(); Physical(w):0035bfa5=01(); RAM(w):0035bfa5=01(); RealRAM(w):002fbfa5=01(); Normal(w):c13a1fa6=00( ); Paged(w):c13a1fa6=00( ); Physical(w):0035bfa6=00( ); RAM(w):0035bfa6=00( ); RealRAM(w):002fbfa6=00( ); Normal(w):c13a1fa7=00( ); Paged(w):c13a1fa7=00( ); Physical(w):0035bfa7=00( ); RAM(w):0035bfa7=00( ); RealRAM(w):002fbfa7=00( ); Normal(w):c13a1fa0=0c( ); Paged(w):c13a1fa0=0c( ); Physical(w):0035bfa0=0c( ); RAM(w):0035bfa0=0c( ); RealRAM(w):002fbfa0=0c( ); Normal(w):c13a1fa1=a2(¢); Paged(w):c13a1fa1=a2(¢); Physical(w):0035bfa1=a2(¢); RAM(w):0035bfa1=a2(¢); RealRAM(w):002fbfa1=a2(¢); Normal(w):c13a1fa2=01(); Paged(w):c13a1fa2=01(); Physical(w):0035bfa2=01(); RAM(w):0035bfa2=01(); RealRAM(w):002fbfa2=01(); Normal(w):c13a1fa3=00( ); Paged(w):c13a1fa3=00( ); Physical(w):0035bfa3=00( ); RAM(w):0035bfa3=00( ); RealRAM(w):002fbfa3=00( ); Normal(w):c13a1f9c=46(F); Paged(w):c13a1f9c=46(F); Physical(w):0035bf9c=46(F); RAM(w):0035bf9c=46(F); RealRAM(w):002fbf9c=46(F); Normal(w):c13a1f9d=02(); Paged(w):c13a1f9d=02(); Physical(w):0035bf9d=02(); RAM(w):0035bf9d=02(); RealRAM(w):002fbf9d=02(); Normal(w):c13a1f9e=00( ); Paged(w):c13a1f9e=00( ); Physical(w):0035bf9e=00( ); RAM(w):0035bf9e=00( ); RealRAM(w):002fbf9e=00( ); Normal(w):c13a1f9f=00( ); Paged(w):c13a1f9f=00( ); Physical(w):0035bf9f=00( ); RAM(w):0035bf9f=00( ); RealRAM(w):002fbf9f=00( ); Normal(w):c13a1f98=17(); Paged(w):c13a1f98=17(); Physical(w):0035bf98=17(); RAM(w):0035bf98=17(); RealRAM(w):002fbf98=17(); Normal(w):c13a1f99=01(); Paged(w):c13a1f99=01(); Physical(w):0035bf99=01(); RAM(w):0035bf99=01(); RealRAM(w):002fbf99=01(); Normal(w):c13a1f9a=00( ); Paged(w):c13a1f9a=00( ); Physical(w):0035bf9a=00( ); RAM(w):0035bf9a=00( ); RealRAM(w):002fbf9a=00( ); Normal(w):c13a1f9b=00( ); Paged(w):c13a1f9b=00( ); Physical(w):0035bf9b=00( ); RAM(w):0035bf9b=00( ); RealRAM(w):002fbf9b=00( ); Normal(w):c13a1f94=22("); Paged(w):c13a1f94=22("); Physical(w):0035bf94=22("); RAM(w):0035bf94=22("); RealRAM(w):002fbf94=22("); Normal(w):c13a1f95=65(e); Paged(w):c13a1f95=65(e); Physical(w):0035bf95=65(e); RAM(w):0035bf95=65(e); RealRAM(w):002fbf95=65(e); Normal(w):c13a1f96=00( ); Paged(w):c13a1f96=00( ); Physical(w):0035bf96=00( ); RAM(w):0035bf96=00( ); RealRAM(w):002fbf96=00( ); Normal(w):c13a1f97=00( ); Paged(w):c13a1f97=00( ); Physical(w):0035bf97=00( ); RAM(w):0035bf97=00( ); RealRAM(w):002fbf97=00( ); Normal(w):c13a1f90=c4(Ä); Paged(w):c13a1f90=c4(Ä); Physical(w):0035bf90=c4(Ä); RAM(w):0035bf90=c4(Ä); RealRAM(w):002fbf90=c4(Ä); Normal(w):c13a1f91=ec(ì); Paged(w):c13a1f91=ec(ì); Physical(w):0035bf91=ec(ì); RAM(w):0035bf91=ec(ì); RealRAM(w):002fbf91=ec(ì); Normal(w):c13a1f92=00( ); Paged(w):c13a1f92=00( ); Physical(w):0035bf92=00( ); RAM(w):0035bf92=00( ); RealRAM(w):002fbf92=00( ); Normal(w):c13a1f93=00( ); Paged(w):c13a1f93=00( ); Physical(w):0035bf93=00( ); RAM(w):0035bf93=00( ); RealRAM(w):002fbf93=00( )
Registers:
EAX: 0000a286 EBX: 01176e77 ECX: 00000137 EDX: 00090001
ESP: 0001a20c EBP: 00001fe4 ESI: 00018370 EDI: 00000097
CS: 0117 DS: 013f ES: 013f FS: 0167 GS: 0000 SS: 013f TR: 0018 LDTR: 00b8
EIP: 00006522 EFLAGS: 00000246
CR0: 80000011 CR1: 00000000 CR2: bffbc01a CR3: 002e9000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000c003765001f7 IDTR: 0000800ac00002ff
FLAGSINFO: 00000000000000vr0n00odItsZ0a0P1c


But the RETFD should pop the values at ESP and ESP+04, not ESP+08 and up at all?
Edit: Hmmm.... It is acting correctly after all? The pop dword [esp+08] pops to ESP+08, then increases ESP by 4(thus ESP is at ESP+04 from that point of view). The next instruction will pop that value first(whatever it is), then proceeding to pop ESP+08 for the segment, which has said strange value popped into it.

Looking upwards for where said value is loaded, at lines:
line:407979 push dword ds:[1320]
line:392076 mov dword ds:[1320],eax

Said EAX value seems to contain the cause of the invalid value. But the instructions are working correctly? There is some weird algorithmic being done right before that, though:
Code: Select all
   RealRAM(p):000ec14a=3e(>); RAM(p):0014c14a=3e(>); Physical(p):0014c14a=3e(>); Paged(p):0000d14a=3e(>); Normal(p):000049aa=3e(>)
MMU: Reading from real(r): 001d3110=7f ()
Reading from RAM(r): 00233110=7f ()
Reading from physical memory(r): 00233110=7f ()
Reading from paged memory(r): 8009c110=7f ()
MMU: Reading from real(r): 001d3111=d1 (Ñ)
Reading from RAM(r): 00233111=d1 (Ñ)
Reading from physical memory(r): 00233111=d1 (Ñ)
Reading from paged memory(r): 8009c111=d1 (Ñ)
MMU: Reading from real(r): 001d3112=a0 ( )
Reading from RAM(r): 00233112=a0 ( )
Reading from physical memory(r): 00233112=a0 ( )
Reading from paged memory(r): 8009c112=a0 ( )
MMU: Reading from real(r): 001d3113=87 (‡)
Reading from RAM(r): 00233113=87 (‡)
Reading from physical memory(r): 00233113=87 (‡)
Reading from paged memory(r): 8009c113=87 (‡)
MMU: Reading from real(r): 001d3114=00 ( )
Reading from RAM(r): 00233114=00 ( )
Reading from physical memory(r): 00233114=00 ( )
Reading from paged memory(r): 8009c114=00 ( )
MMU: Reading from real(r): 001d3115=fb (û)
Reading from RAM(r): 00233115=fb (û)
Reading from physical memory(r): 00233115=fb (û)
Reading from paged memory(r): 8009c115=fb (û)
MMU: Reading from real(r): 001d3116=00 ( )
Reading from RAM(r): 00233116=00 ( )
Reading from physical memory(r): 00233116=00 ( )
Reading from paged memory(r): 8009c116=00 ( )
MMU: Reading from real(r): 001d3117=00 ( )
Reading from RAM(r): 00233117=00 ( )
Reading from physical memory(r): 00233117=00 ( )
Reading from paged memory(r): 8009c117=00 ( )
0117:0000499b CA 02 00 retf 0002   RealRAM(r):00b4121c=75(u); RAM(r):00ba121c=75(u); Physical(r):00ba121c=75(u); Paged(r):0001a21c=75(u); RealRAM(r):00b4121d=6a(j); RAM(r):00ba121d=6a(j); Physical(r):00ba121d=6a(j); Paged(r):0001a21d=6a(j); RealRAM(r):00b4121e=17(); RAM(r):00ba121e=17(); Physical(r):00ba121e=17(); Paged(r):0001a21e=17(); RealRAM(r):00b4121f=01(); RAM(r):00ba121f=01(); Physical(r):00ba121f=01(); Paged(r):0001a21f=01()
Registers:
EAX: 0001014f EBX: 0000014f ECX: 000000f3 EDX: 00000000
ESP: 00001eac EBP: 00001fe4 ESI: 00000081 EDI: 000003b2
CS: 0117 DS: 012f ES: 00bf FS: 0000 GS: 0000 SS: 0097 TR: 0018 LDTR: 00b8
EIP: 0000499b EFLAGS: 00000246
CR0: 80000011 CR1: 00000000 CR2: 80124000 CR3: 002e9000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000c003765001f7 IDTR: 0000800ac00002ff
FLAGSINFO: 00000000000000vr0n00odItsZ0a0P1c
0117:00006a75 0B C0 or ax,ax   RealRAM(p):000ee215=0b( ); RAM(p):0014e215=0b( ); Physical(p):0014e215=0b( ); Paged(p):0000f215=0b( ); Normal(p):00006a75=0b( ); RealRAM(p):000ee216=c0(À); RAM(p):0014e216=c0(À); Physical(p):0014e216=c0(À); Paged(p):0000f216=c0(À); Normal(p):00006a76=c0(À); RealRAM(p):000ee217=0c( ); RAM(p):0014e217=0c( ); Physical(p):0014e217=0c( ); Paged(p):0000f217=0c( ); Normal(p):00006a77=0c( ); RealRAM(p):000ee218=07(); RAM(p):0014e218=07(); Physical(p):0014e218=07(); Paged(p):0000f218=07(); Normal(p):00006a78=07(); RealRAM(p):000ee219=26(&); RAM(p):0014e219=26(&); Physical(p):0014e219=26(&); Paged(p):0000f219=26(&); Normal(p):00006a79=26(&); RealRAM(p):000ee21a=a3(£); RAM(p):0014e21a=a3(£); Physical(p):0014e21a=a3(£); Paged(p):0000f21a=a3(£); Normal(p):00006a7a=a3(£); RealRAM(p):000ee21b=08(); RAM(p):0014e21b=08(); Physical(p):0014e21b=08(); Paged(p):0000f21b=08(); Normal(p):00006a7b=08(); RealRAM(p):000ee21c=00( ); RAM(p):0014e21c=00( ); Physical(p):0014e21c=00( ); Paged(p):0000f21c=00( ); Normal(p):00006a7c=00( ); RealRAM(p):000ee21d=83(ƒ); RAM(p):0014e21d=83(ƒ); Physical(p):0014e21d=83(ƒ); Paged(p):0000f21d=83(ƒ); Normal(p):00006a7d=83(ƒ); RealRAM(p):000ee21e=c0(À); RAM(p):0014e21e=c0(À); Physical(p):0014e21e=c0(À); Paged(p):0000f21e=c0(À); Normal(p):00006a7e=c0(À); RealRAM(p):000ee21f=08(); RAM(p):0014e21f=08(); Physical(p):0014e21f=08(); Paged(p):0000f21f=08(); Normal(p):00006a7f=08(); RealRAM(p):000ee220=26(&); RAM(p):0014e220=26(&); Physical(p):0014e220=26(&); Paged(p):0000f220=26(&); Normal(p):00006a80=26(&); RealRAM(p):000ee221=a3(£); RAM(p):0014e221=a3(£); Physical(p):0014e221=a3(£); Paged(p):0000f221=a3(£); Normal(p):00006a81=a3(£); RealRAM(p):000ee222=0a( ); RAM(p):0014e222=0a( ); Physical(p):0014e222=0a( ); Paged(p):0000f222=0a( ); Normal(p):00006a82=0a( ); RealRAM(p):000ee223=00( ); RAM(p):0014e223=00( ); Physical(p):0014e223=00( ); Paged(p):0000f223=00( ); Normal(p):00006a83=00( ); RealRAM(p):000ee224=83(ƒ); RAM(p):0014e224=83(ƒ); Physical(p):0014e224=83(ƒ); Paged(p):0000f224=83(ƒ); Normal(p):00006a84=83(ƒ)
Registers:
EAX: 0001014f EBX: 0000014f ECX: 000000f3 EDX: 00000000
ESP: 00001eb2 EBP: 00001fe4 ESI: 00000081 EDI: 000003b2
CS: 0117 DS: 012f ES: 00bf FS: 0000 GS: 0000 SS: 0097 TR: 0018 LDTR: 00b8
EIP: 00006a75 EFLAGS: 00000246
CR0: 80000011 CR1: 00000000 CR2: 80124000 CR3: 002e9000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000c003765001f7 IDTR: 0000800ac00002ff
FLAGSINFO: 00000000000000vr0n00odItsZ0a0P1c
0117:00006a77 0C 07 or al,07   RealRAM(p):000ee225=c0(À); RAM(p):0014e225=c0(À); Physical(p):0014e225=c0(À); Paged(p):0000f225=c0(À); Normal(p):00006a85=c0(À); RealRAM(p):000ee226=08(); RAM(p):0014e226=08(); Physical(p):0014e226=08(); Paged(p):0000f226=08(); Normal(p):00006a86=08()
Registers:
EAX: 0001014f EBX: 0000014f ECX: 000000f3 EDX: 00000000
ESP: 00001eb2 EBP: 00001fe4 ESI: 00000081 EDI: 000003b2
CS: 0117 DS: 012f ES: 00bf FS: 0000 GS: 0000 SS: 0097 TR: 0018 LDTR: 00b8
EIP: 00006a77 EFLAGS: 00000202
CR0: 80000011 CR1: 00000000 CR2: 80124000 CR3: 002e9000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000c003765001f7 IDTR: 0000800ac00002ff
FLAGSINFO: 00000000000000vr0n00odItsz0a0p1c
   RealRAM(p):000ee227=26(&); RAM(p):0014e227=26(&); Physical(p):0014e227=26(&); Paged(p):0000f227=26(&); Normal(p):00006a87=26(&); RealRAM(p):000ee228=a3(£); RAM(p):0014e228=a3(£); Physical(p):0014e228=a3(£); Paged(p):0000f228=a3(£); Normal(p):00006a88=a3(£)
0117:00006a79 26 A3 08 00 mov word es:[0008],ax   Paged(w):000087a8=4f(O); Physical(w):00b8e7a8=4f(O); RAM(w):00b8e7a8=4f(O); RealRAM(w):00b2e7a8=4f(O); Paged(w):000087a9=01(); Physical(w):00b8e7a9=01(); RAM(w):00b8e7a9=01(); RealRAM(w):00b2e7a9=01()
Registers:
EAX: 0001014f EBX: 0000014f ECX: 000000f3 EDX: 00000000
ESP: 00001eb2 EBP: 00001fe4 ESI: 00000081 EDI: 000003b2
CS: 0117 DS: 012f ES: 00bf FS: 0000 GS: 0000 SS: 0097 TR: 0018 LDTR: 00b8
EIP: 00006a79 EFLAGS: 00000202
CR0: 80000011 CR1: 00000000 CR2: 80124000 CR3: 002e9000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000c003765001f7 IDTR: 0000800ac00002ff
FLAGSINFO: 00000000000000vr0n00odItsz0a0p1c
0117:00006a7d 83 C0 08 add ax,0008   RealRAM(p):000ee229=0c( ); RAM(p):0014e229=0c( ); Physical(p):0014e229=0c( ); Paged(p):0000f229=0c( ); Normal(p):00006a89=0c( ); RealRAM(p):000ee22a=00( ); RAM(p):0014e22a=00( ); Physical(p):0014e22a=00( ); Paged(p):0000f22a=00( ); Normal(p):00006a8a=00( ); RealRAM(p):000ee22b=66(f); RAM(p):0014e22b=66(f); Physical(p):0014e22b=66(f); Paged(p):0000f22b=66(f); Normal(p):00006a8b=66(f); RealRAM(p):000ee22c=b8(¸); RAM(p):0014e22c=b8(¸); Physical(p):0014e22c=b8(¸); Paged(p):0000f22c=b8(¸); Normal(p):00006a8c=b8(¸)
Registers:
EAX: 0001014f EBX: 0000014f ECX: 000000f3 EDX: 00000000
ESP: 00001eb2 EBP: 00001fe4 ESI: 00000081 EDI: 000003b2
CS: 0117 DS: 012f ES: 00bf FS: 0000 GS: 0000 SS: 0097 TR: 0018 LDTR: 00b8
EIP: 00006a7d EFLAGS: 00000202
CR0: 80000011 CR1: 00000000 CR2: 80124000 CR3: 002e9000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000c003765001f7 IDTR: 0000800ac00002ff
FLAGSINFO: 00000000000000vr0n00odItsz0a0p1c
   RealRAM(p):000ee22d=24($); RAM(p):0014e22d=24($); Physical(p):0014e22d=24($); Paged(p):0000f22d=24($); Normal(p):00006a8d=24($); RealRAM(p):000ee22e=65(e); RAM(p):0014e22e=65(e); Physical(p):0014e22e=65(e); Paged(p):0000f22e=65(e); Normal(p):00006a8e=65(e); RealRAM(p):000ee22f=00( ); RAM(p):0014e22f=00( ); Physical(p):0014e22f=00( ); Paged(p):0000f22f=00( ); Normal(p):00006a8f=00( )
0117:00006a80 26 A3 0A 00 mov word es:[000a],ax   Paged(w):000087aa=57(W); Physical(w):00b8e7aa=57(W); RAM(w):00b8e7aa=57(W); RealRAM(w):00b2e7aa=57(W); Paged(w):000087ab=01(); Physical(w):00b8e7ab=01(); RAM(w):00b8e7ab=01(); RealRAM(w):00b2e7ab=01()
Registers:
EAX: 00010157 EBX: 0000014f ECX: 000000f3 EDX: 00000000
ESP: 00001eb2 EBP: 00001fe4 ESI: 00000081 EDI: 000003b2
CS: 0117 DS: 012f ES: 00bf FS: 0000 GS: 0000 SS: 0097 TR: 0018 LDTR: 00b8
EIP: 00006a80 EFLAGS: 00000212
CR0: 80000011 CR1: 00000000 CR2: 80124000 CR3: 002e9000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000c003765001f7 IDTR: 0000800ac00002ff
FLAGSINFO: 00000000000000vr0n00odItsz0A0p1c
0117:00006a84 83 C0 08 add ax,0008   RealRAM(p):000ee230=00( ); RAM(p):0014e230=00( ); Physical(p):0014e230=00( ); Paged(p):0000f230=00( ); Normal(p):00006a90=00( ); RealRAM(p):000ee231=66(f); RAM(p):0014e231=66(f); Physical(p):0014e231=66(f); Paged(p):0000f231=66(f); Normal(p):00006a91=66(f); RealRAM(p):000ee232=03(); RAM(p):0014e232=03(); Physical(p):0014e232=03(); Paged(p):0000f232=03(); Normal(p):00006a92=03(); RealRAM(p):000ee233=06(); RAM(p):0014e233=06(); Physical(p):0014e233=06(); Paged(p):0000f233=06(); Normal(p):00006a93=06()
Registers:
EAX: 00010157 EBX: 0000014f ECX: 000000f3 EDX: 00000000
ESP: 00001eb2 EBP: 00001fe4 ESI: 00000081 EDI: 000003b2
CS: 0117 DS: 012f ES: 00bf FS: 0000 GS: 0000 SS: 0097 TR: 0018 LDTR: 00b8
EIP: 00006a84 EFLAGS: 00000212
CR0: 80000011 CR1: 00000000 CR2: 80124000 CR3: 002e9000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000c003765001f7 IDTR: 0000800ac00002ff
FLAGSINFO: 00000000000000vr0n00odItsz0A0p1c
   RealRAM(p):000ee234=fc(ü); RAM(p):0014e234=fc(ü); Physical(p):0014e234=fc(ü); Paged(p):0000f234=fc(ü); Normal(p):00006a94=fc(ü); RealRAM(p):000ee235=12(); RAM(p):0014e235=12(); Physical(p):0014e235=12(); Paged(p):0000f235=12(); Normal(p):00006a95=12(); RealRAM(p):000ee236=66(f); RAM(p):0014e236=66(f); Physical(p):0014e236=66(f); Paged(p):0000f236=66(f); Normal(p):00006a96=66(f)
0117:00006a87 26 A3 0C 00 mov word es:[000c],ax   Paged(w):000087ac=5f(_); Physical(w):00b8e7ac=5f(_); RAM(w):00b8e7ac=5f(_); RealRAM(w):00b2e7ac=5f(_); Paged(w):000087ad=01(); Physical(w):00b8e7ad=01(); RAM(w):00b8e7ad=01(); RealRAM(w):00b2e7ad=01()
Registers:
EAX: 0001015f EBX: 0000014f ECX: 000000f3 EDX: 00000000
ESP: 00001eb2 EBP: 00001fe4 ESI: 00000081 EDI: 000003b2
CS: 0117 DS: 012f ES: 00bf FS: 0000 GS: 0000 SS: 0097 TR: 0018 LDTR: 00b8
EIP: 00006a87 EFLAGS: 00000206
CR0: 80000011 CR1: 00000000 CR2: 80124000 CR3: 002e9000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000c003765001f7 IDTR: 0000800ac00002ff
FLAGSINFO: 00000000000000vr0n00odItsz0a0P1c
0117:00006a8b 66 B8 24 65 00 00 mov eax,00006524   RealRAM(p):000ee237=a3(£); RAM(p):0014e237=a3(£); Physical(p):0014e237=a3(£); Paged(p):0000f237=a3(£); Normal(p):00006a97=a3(£); RealRAM(p):000ee238=20( ); RAM(p):0014e238=20( ); Physical(p):0014e238=20( ); Paged(p):0000f238=20( ); Normal(p):00006a98=20( ); RealRAM(p):000ee239=13(); RAM(p):0014e239=13(); Physical(p):0014e239=13(); Paged(p):0000f239=13(); Normal(p):00006a99=13(); RealRAM(p):000ee23a=8d(); RAM(p):0014e23a=8d(); Physical(p):0014e23a=8d(); Paged(p):0000f23a=8d(); Normal(p):00006a9a=8d()
Registers:
EAX: 0001015f EBX: 0000014f ECX: 000000f3 EDX: 00000000
ESP: 00001eb2 EBP: 00001fe4 ESI: 00000081 EDI: 000003b2
CS: 0117 DS: 012f ES: 00bf FS: 0000 GS: 0000 SS: 0097 TR: 0018 LDTR: 00b8
EIP: 00006a8b EFLAGS: 00000206
CR0: 80000011 CR1: 00000000 CR2: 80124000 CR3: 002e9000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000c003765001f7 IDTR: 0000800ac00002ff
FLAGSINFO: 00000000000000vr0n00odItsz0a0P1c
0117:00006a91 66 03 06 FC 12 add eax,dword ds:[12fc]   RealRAM(p):000ee23b=46(F); RAM(p):0014e23b=46(F); Physical(p):0014e23b=46(F); Paged(p):0000f23b=46(F); Normal(p):00006a9b=46(F); RealRAM(p):000ee23c=d0(Ð); RAM(p):0014e23c=d0(Ð); Physical(p):0014e23c=d0(Ð); Paged(p):0000f23c=d0(Ð); Normal(p):00006a9c=d0(Ð); RealRAM(p):000ee23d=50(P); RAM(p):0014e23d=50(P); Physical(p):0014e23d=50(P); Paged(p):0000f23d=50(P); Normal(p):00006a9d=50(P); RealRAM(p):000ee23e=e8(è); RAM(p):0014e23e=e8(è); Physical(p):0014e23e=e8(è); Paged(p):0000f23e=e8(è); Normal(p):00006a9e=e8(è); RealRAM(p):000ee23f=89(‰); RAM(p):0014e23f=89(‰); Physical(p):0014e23f=89(‰); Paged(p):0000f23f=89(‰); Normal(p):00006a9f=89(‰); RealRAM(p):000ee240=06(); RAM(p):0014e240=06(); Physical(p):0014e240=06(); Paged(p):0000f240=06(); Normal(p):00006aa0=06(); RealRAM(r):000f5c1c=a0( ); RAM(r):00155c1c=a0( ); Physical(r):00155c1c=a0( ); Paged(r):00016c1c=a0( ); RealRAM(r):000f5c1d=87(‡); RAM(r):00155c1d=87(‡); Physical(r):00155c1d=87(‡); Paged(r):00016c1d=87(‡); RealRAM(r):000f5c1e=00( ); RAM(r):00155c1e=00( ); Physical(r):00155c1e=00( ); Paged(r):00016c1e=00( ); RealRAM(r):000f5c1f=00( ); RAM(r):00155c1f=00( ); Physical(r):00155c1f=00( ); Paged(r):00016c1f=00( )
Registers:
EAX: 00006524 EBX: 0000014f ECX: 000000f3 EDX: 00000000
ESP: 00001eb2 EBP: 00001fe4 ESI: 00000081 EDI: 000003b2
CS: 0117 DS: 012f ES: 00bf FS: 0000 GS: 0000 SS: 0097 TR: 0018 LDTR: 00b8
EIP: 00006a91 EFLAGS: 00000206
CR0: 80000011 CR1: 00000000 CR2: 80124000 CR3: 002e9000
DR0: 00000000 DR1: 00000000 DR2: 00000000 DR3: 00000000
DR6: 00000000 DR7: 00000000
GDTR: 0000c003765001f7 IDTR: 0000800ac00002ff
FLAGSINFO: 00000000000000vr0n00odItsz0a0P1c


It looks like some 16-bit windows segment algorithmic(adding 8 for the next descriptor to use and storing it), but then proceeds to perform weird calculations?
It does reveal something that might be interesting: the code block that's executed is seemingly loaded at 87A0, length D17F, type FB(privilege 3 code segment, non-conforming, readable, accessed). So, some code running at address 87A0 is the code block that's executing(in the current virtual address space). Said code has length D17F.
Is there any code module in Windows 95A with that length(53631 bytes)?

Edit: Just might have found the code that's causing this crash: at KRNL386.EXE, file offset 89B5!

So there's somehow some weird error in the 386 kernel that's causing this? Strange...
superfury
l33t
 
Posts: 3288
Joined: 2014-3-08 @ 11:25
Location: Netherlands


Return to PC Emulation

Who is online

Users browsing this forum: superfury and 2 guests