VOGONS


First post, by superfury

User metadata
Rank l33t++
Rank
l33t++

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/unipcemu/src/ … pu/protection.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?

Last edited by superfury on 2019-11-21, 09:00. Edited 3 times in total.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 1 of 45, by superfury

User metadata
Rank l33t++
Rank
l33t++

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)).

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 2 of 45, by superfury

User metadata
Rank l33t++
Rank
l33t++

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?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 3 of 45, by superfury

User metadata
Rank l33t++
Rank
l33t++

This is the current segment write handler for all cases:

/*

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!
}

Show last 788 lines
	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.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 4 of 45, by superfury

User metadata
Rank l33t++
Rank
l33t++

The crash happens at 117:6622. Anyone knows what vxd LDT 110h is?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 5 of 45, by superfury

User metadata
Rank l33t++
Rank
l33t++

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.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 6 of 45, by superfury

User metadata
Rank l33t++
Rank
l33t++

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):

Filename
debugger_segment117_WIN95Acrash.7z
File size
1.59 MiB
Downloads
53 downloads
File comment
Windows 95A crashing at 117:6522
File license
Fair use/fair dealing exception

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

	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 ( )
Show last 61 lines
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:

	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
Show last 86 lines
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(linear memory address f215)! That seems to start at line 391973?

So there's somehow some weird error in the 16-bit module 386 kernel that's causing this? Strange...

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 7 of 45, by superfury

User metadata
Rank l33t++
Rank
l33t++

Looking through INT calls, I see stuff like idt being set-get, DPMI calls. But the final one is some driver being requested its entry point(VTDAPI, http://www.ctyme.com/intr/rb-4576.htm, at log line 407358).

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 8 of 45, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just tried reinstalling Windows 95 a from the CD-ROM disk image.

Now Windows crashes with the old "Windows protection error. You need to restart your computer." again?

Edit: Looking at the difference between the old(before the last few patches, diffing between the setup from the last commit before 2019-07-31 07:28 and the current version(at commit 2019-11-14 22:14)) and new VMM32.VXD, it's contents are almost completely changed?
Edit: Reversed the VMM32.VXD changes by reinstalling using the default options. Again #GP fault at offset 6622h.

Last edited by superfury on 2019-11-19, 11:39. Edited 2 times in total.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 9 of 45, by superfury

User metadata
Rank l33t++
Rank
l33t++

Interestingly enough, I still see the RETF to segment E0 during the start of the Windows 95 setup? Is that supposed to happen? It starts the moment the GUI is started after running setup.exe from the MS-DOS prompt or dos-based installer(with the 95A setup bootdisk), directly after copying files for the GUI/wizard is finished and the GUI starts and switches to 640x480x16 mode? Anyone?

It stops being thrown during the preparation progress bar of the setup wizard, but returns faulting after it's finished that part. Don't know if it still happens after that(didn't check).

Edit: It's a 16-bit RETF returning to E0:140C. Anyone knows what this is? It even happens once before the GUI is loaded during the Windows 95 setup?
Edit: Said segment has a limit of 0x4330?
Edit: SP is 0xFF0 after it's popped, so at 0xFEE there's the back return value?
Edit: SS is 0x2C7 for that return. It has a limit of 0xFFF, with a base address of 0x325020(16MB physical RAM installed, ~15.3MB reported by the BIOS during POST(640K base, 14MB extended)). So the invalid return value is at physical memory address 0x32600E.
Edit: CS is 0x367 at that point(in protected mode). Anyone knows what said code might be?
Edit: I see a RETF from 2EF:AD9A executing a plain RETF to return to 367:AD9B? ESP is left at FE4 at that time?
Edit: Then from 367:2177 to 367:ADAB?
Edit: Then from 367:D65(SP=FE8) to 367:ADE2?
Edit: Then from 367:2AEC(SP=FE8) to 367:ADF5?
Edit: Then from 367:D64(SP=FE8) to 367:AE0C?
Edit: Then from 367:AE1F(SP=FE8) to 367:AE1F?
Edit: Then from 53:2B9A(SP=F8A) to 367:35F9 during a IRET?
Stopped looking at it after that.

So it's apparently something that is used a lot during the setup loading(above is all before the GUI starts).

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 10 of 45, by superfury

User metadata
Rank l33t++
Rank
l33t++

Hmmm... Looking upwards in the KRNL386 log, the (invalid?) value seems to originate from some function setting the value, starting at 137:00004e84?

Edit: The weird value that's added(87A0h) to the constant, it looks like it's loading the value to add from a constant 16-bit value that seems to be from an entry's base address in the LDT?
I see 0117:00004e8d 2E 8E 1E 06 00 mov ds,word cs:[0006]. Looking at what's it loading it's descriptor in the LDT from(selector 87h from memory location 8009c087h), it can be deduced that the LDT(b8h) is pointing to 8009c000 for it's used LDT table).
EBX is 110 during that part, so it's selecting the segment descriptor that's loaded in the code segment in the LDT.
I see, below that, 0117:00004e95 8B 47 02 mov ax,word ds:[bx+02]. So it's loading the 117h code segment (the code segment descriptor of the KRNL386's code) low 16-bits of it's base address into ax, to later be moved to address ds:[12fc], which is linear address 16c1c. DX(index 4 in DL, index 7 in DH) contains the upper part of the starting address. That's moved to 0x12fe. So the dword at 12fc(at linear address 16c1c) contains the base address of segment selector 117h at that point.

So, the invalid selector is last written at 0117:0000651c 67 66 8F 44 24 08 pop dword ss:[esp+08].
Said source is 0001a209=ec. Looking up for it's write, it's:
0117:000064c9 66 FF 36 20 13 push dword ds:[1320]

Then, looking at the setting of said dword, I find:
0117:00006a96 66 A3 20 13 mov dword ds:[1320],eax

The instruction before that is:
0117:00006a91 66 03 06 FC 12 add eax,dword ds:[12fc]
Where it's adding the base address of segment 117h to EAX.

And just before that, there's:
0117:00006a8b 66 B8 24 65 00 00 mov eax,00006524

So, 6524+base address(assumed within 16-bit range)=selector to retfd to?

Edit: So, the dword at ds:[1320] is actually the 0x6524th byte in linear address space? So perhaps some entry point of 32-bit code?
The weird thing is that it's popping it into the CS location on the stack during the RETF instead of the EIP location?

Edit: So, the RETFD pops EIP,CS from the stack at SP=1a20c, which is linear memory location 1a20c as well. So, SS must be 1MB or 4GB with a base of 0. That's easy to deduce.

The final 2 instructions weirdly affect each other? First it pops the top of the stack(the invalid linear address) into 2 stack pops ahead of esp(+8). Then it retfds into the segment value just popped into ss:[esp+08]?

Is there some special way [esp+08] is handled when popping to such an address? Is esp first incremented and only after that the value written to [esp+08]? Or is the address first calculated, a value popped, then recalculated? So it would be popping directly after the return selector?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 11 of 45, by superfury

User metadata
Rank l33t++
Rank
l33t++

OK. So I was suspiscious about the pop dword ss:[esp+08] just before the retfd, which was crashing on it...

So I looked the pop instruction up (https://c9x.me/x86/html/file_module_x86_id_248.html)

If the ESP register is used as a base register for addressing a destination operand in memory, the POP instruction computes the effective address of the operand after it increments the ESP register. For the case of a 16-bit stack where ESP wraps to 0h as a result of the POP instruction, the resulting location of the memory write is processor-family-specific.

The case of this crash is exactly that: the EA of the modr/m needs to recalculated before the memory access is made to write the result. That way, the return segment selector is remained unharmed and should work properly! That's a very hidden bug indeed!

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 12 of 45, by superfury

User metadata
Rank l33t++
Rank
l33t++

Hmmm... The fix didn't help? It still crashed like before(or at least at the same location)? Hmmmm...
Edit: Whoops. The whole memory checking(including paging and segmentation faults) and recalc of the modr/m offset(required for the POP [(E)SP] instructions) wasn't being applied due to the wrong step variable being used 😖 That's fixed now.

Edit: Yay! Windows 95 manages to boot into the GUI now! 😁 😁 😁 😁 😁
Edit: Mouse working properly:D

Edit: Now detecting hardware...

1181-Windows 95 setup in UniPCemu first boot.jpg
Filename
1181-Windows 95 setup in UniPCemu first boot.jpg
File size
167.7 KiB
Views
1359 views
File comment
Windows 95 booting fully for the first time in UniPCemu!
File license
Fair use/fair dealing exception

Boolog so far:

[0002B63C] Loading Device = C:\WINDOWS\HIMEM.SYS
[0002B63E] LoadSuccess = C:\WINDOWS\HIMEM.SYS
[0002B63E] Loading Device = C:\WINDOWS\IFSHLP.SYS
[0002B63E] LoadSuccess = C:\WINDOWS\IFSHLP.SYS
[0002B63F] Loading Device = C:\WINDOWS\SETVER.EXE
[0002B63F] LoadSuccess = C:\WINDOWS\SETVER.EXE
[0002B651] Loading Vxd = VMM
[0002B663] LoadSuccess = VMM
[0002B664] Loading Vxd = CONFIGMG
[0002B66A] LoadSuccess = CONFIGMG
[0002B66A] Loading Vxd = VSHARE
[0002B66C] LoadSuccess = VSHARE
[0002B66C] Loading Vxd = VWIN32
[0002B66F] LoadSuccess = VWIN32
[0002B66F] Loading Vxd = VFBACKUP
[0002B670] LoadSuccess = VFBACKUP
[0002B670] Loading Vxd = VCOMM
[0002B672] LoadSuccess = VCOMM
[0002B672] Loading Vxd = COMBUFF
[0002B672] LoadSuccess = COMBUFF
[0002B672] Loading Vxd = IFSMGR
[0002B680] LoadSuccess = IFSMGR
[0002B680] Loading Vxd = IOS
[0002B687] LoadSuccess = IOS
[0002B687] Loading Vxd = SPOOLER
[0002B689] LoadSuccess = SPOOLER
[0002B689] Loading Vxd = VFAT
[0002B68E] LoadSuccess = VFAT
[0002B68E] Loading Vxd = VCACHE
[0002B690] LoadSuccess = VCACHE
[0002B690] Loading Vxd = VCOND
[0002B692] LoadSuccess = VCOND
[0002B692] Loading Vxd = VCDFSD
[0002B694] LoadSuccess = VCDFSD
[0002B694] Loading Vxd = VXDLDR
[0002B696] LoadSuccess = VXDLDR
[0002B696] Loading Vxd = VDEF
[0002B697] LoadSuccess = VDEF
[0002B697] Loading Vxd = VPICD
[0002B699] LoadSuccess = VPICD
[0002B699] Loading Vxd = VTD
[0002B69A] LoadSuccess = VTD
[0002B69A] Loading Vxd = REBOOT
[0002B69B] LoadSuccess = REBOOT
[0002B69C] Loading Vxd = VDMAD
[0002B69D] LoadSuccess = VDMAD
[0002B69D] Loading Vxd = VSD
[0002B69E] LoadSuccess = VSD
[0002B69E] Loading Vxd = V86MMGR
[0002B6A3] LoadSuccess = V86MMGR
[0002B6A3] Loading Vxd = PAGESWAP
[0002B6A4] LoadSuccess = PAGESWAP
[0002B6A4] Loading Vxd = DOSMGR
[0002B6A9] LoadSuccess = DOSMGR
[0002B6A9] Loading Vxd = VMPOLL
[0002B6AA] LoadSuccess = VMPOLL
[0002B6AA] Loading Vxd = SHELL
[0002B6AE] LoadSuccess = SHELL
[0002B6AE] Loading Vxd = PARITY
[0002B6AE] LoadSuccess = PARITY
Show last 438 lines
[0002B6AE] Loading Vxd = BIOSXLAT
[0002B6AF] LoadSuccess = BIOSXLAT
[0002B6AF] Loading Vxd = VMCPD
[0002B6B0] LoadSuccess = VMCPD
[0002B6B0] Loading Vxd = VTDAPI
[0002B6B1] LoadSuccess = VTDAPI
[0002B6B2] Loading Vxd = PERF
[0002B6B3] LoadSuccess = PERF
[0002B6B3] Loading Vxd = ebios
[0002B6B4] LoadSuccess = ebios
[0002B6B4] Loading Vxd = vshare
[0002B6B4] LoadFailed = vshare
[0002B6B4] Loading Vxd = dynapage
[0002B6B6] LoadSuccess = dynapage
[0002B6B6] Loading Vxd = vcd
[0002B6B8] LoadSuccess = vcd
[0002B6B8] Loading Vxd = vpd
[0002B6B9] LoadSuccess = vpd
[0002B6B9] Loading Vxd = int13
[0002B6BA] LoadSuccess = int13
[0002B6BA] Loading Vxd = vdd
[0002B6C0] LoadSuccess = vdd
[0002B6C0] Loading Vxd = vflatd
[0002B6C0] LoadSuccess = vflatd
[0002B6C0] Loading Vxd = vmouse
[0002B6C3] LoadSuccess = vmouse
[0002B6C3] Loading Vxd = msmouse.vxd
[0002B6C4] LoadSuccess = msmouse.vxd
[0002B6C4] Loading Vxd = vkd
[0002B6C6] LoadSuccess = vkd
[0002B6C6] Loading Vxd = enable
[0002B6C9] LoadSuccess = enable
[0002B6CF] SYSCRITINIT = VMM
[0002B6D0] SYSCRITINITSUCCESS = VMM
[0002B6D0] SYSCRITINIT = VCACHE
[0002B6D0] SYSCRITINITSUCCESS = VCACHE
[0002B6D0] SYSCRITINIT = PERF
[0002B6D0] SYSCRITINITSUCCESS = PERF
[0002B6D1] SYSCRITINIT = VPICD
[0002B6D1] SYSCRITINITSUCCESS = VPICD
[0002B6D1] SYSCRITINIT = VTD
[0002B6D1] SYSCRITINITSUCCESS = VTD
[0002B6D1] SYSCRITINIT = VXDLDR
[0002B6D2] SYSCRITINITSUCCESS = VXDLDR
[0002B6D2] SYSCRITINIT = CONFIGMG
[0002B6D2] SYSCRITINITSUCCESS = CONFIGMG
[0002B6D2] SYSCRITINIT = VCDFSD
[0002B6D2] SYSCRITINITSUCCESS = VCDFSD
[0002B6D3] SYSCRITINIT = IOS
[0002B6D3] SYSCRITINITSUCCESS = IOS
[0002B6D3] SYSCRITINIT = PAGEFILE
[0002B6D3] SYSCRITINITSUCCESS = PAGEFILE
[0002B6D4] SYSCRITINIT = PAGESWAP
[0002B6D4] SYSCRITINITSUCCESS = PAGESWAP
[0002B6D4] SYSCRITINIT = PARITY
[0002B6D4] SYSCRITINITSUCCESS = PARITY
[0002B6D4] SYSCRITINIT = REBOOT
[0002B6D4] SYSCRITINITSUCCESS = REBOOT
[0002B6D5] SYSCRITINIT = EBIOS
[0002B6D5] SYSCRITINITSUCCESS = EBIOS
[0002B6D5] SYSCRITINIT = VDD
[0002B6D6] SYSCRITINITSUCCESS = VDD
[0002B6D6] SYSCRITINIT = VSD
[0002B6D6] SYSCRITINITSUCCESS = VSD
[0002B6D6] SYSCRITINIT = COMBUFF
[0002B6D6] SYSCRITINITSUCCESS = COMBUFF
[0002B6D6] SYSCRITINIT = VCD
[0002B6D7] SYSCRITINITSUCCESS = VCD
[0002B6D7] SYSCRITINIT = VMOUSE
[0002B6D7] SYSCRITINITSUCCESS = VMOUSE
[0002B6D8] SYSCRITINIT = MSMINI
[0002B6D8] SYSCRITINITSUCCESS = MSMINI
[0002B6D8] SYSCRITINIT = VKD
[0002B6D8] SYSCRITINITSUCCESS = VKD
[0002B6D8] SYSCRITINIT = ENABLE
[0002B6D8] SYSCRITINITSUCCESS = ENABLE
[0002B6D9] SYSCRITINIT = VPD
[0002B6D9] SYSCRITINITSUCCESS = VPD
[0002B6D9] SYSCRITINIT = INT13
[0002B6D9] SYSCRITINITSUCCESS = INT13
[0002B6D9] SYSCRITINIT = VMCPD
[0002B6DA] SYSCRITINITSUCCESS = VMCPD
[0002B6DA] SYSCRITINIT = BIOSXLAT
[0002B6DA] SYSCRITINITSUCCESS = BIOSXLAT
[0002B6DA] SYSCRITINIT = DOSMGR
[0002B6DA] SYSCRITINITSUCCESS = DOSMGR
[0002B6DA] SYSCRITINIT = VSHARE
[0002B6DB] SYSCRITINITSUCCESS = VSHARE
[0002B6DB] SYSCRITINIT = VMPOLL
[0002B6DB] SYSCRITINITSUCCESS = VMPOLL
[0002B6DB] SYSCRITINIT = VWIN32
[0002B6DB] SYSCRITINITSUCCESS = VWIN32
[0002B6DC] SYSCRITINIT = VCOMM
[0002B6DC] SYSCRITINITSUCCESS = VCOMM
[0002B6DC] SYSCRITINIT = VCOND
[0002B6DC] SYSCRITINITSUCCESS = VCOND
[0002B6DC] SYSCRITINIT = VTDAPI
[0002B6DC] SYSCRITINITSUCCESS = VTDAPI
[0002B6DD] SYSCRITINIT = VFLATD
[0002B6DD] SYSCRITINITSUCCESS = VFLATD
[0002B6DD] SYSCRITINIT = VDMAD
[0002B6DD] SYSCRITINITSUCCESS = VDMAD
[0002B6DE] SYSCRITINIT = V86MMGR
[0002B6DE] SYSCRITINITSUCCESS = V86MMGR
[0002B6DE] SYSCRITINIT = SPOOLER
[0002B6DE] SYSCRITINITSUCCESS = SPOOLER
[0002B6DE] SYSCRITINIT = VFAT
[0002B6DE] SYSCRITINITSUCCESS = VFAT
[0002B6DF] SYSCRITINIT = VDEF
[0002B6DF] SYSCRITINITSUCCESS = VDEF
[0002B6DF] SYSCRITINIT = IFSMGR
[0002B6DF] SYSCRITINITSUCCESS = IFSMGR
[0002B6E0] SYSCRITINIT = VFBACKUP
[0002B6E0] SYSCRITINITSUCCESS = VFBACKUP
[0002B6E0] SYSCRITINIT = SHELL
[0002B6E0] SYSCRITINITSUCCESS = SHELL
[0002B6E1] DEVICEINIT = VMM
[0002B6E1] DEVICEINITSUCCESS = VMM
[0002B6E1] DEVICEINIT = VCACHE
[0002B6E1] DEVICEINITSUCCESS = VCACHE
[0002B6E3] DEVICEINIT = PERF
[0002B6E3] DEVICEINITSUCCESS = PERF
[0002B6E4] DEVICEINIT = VPICD
[0002B6E4] DEVICEINITSUCCESS = VPICD
[0002B6E5] DEVICEINIT = VTD
[0002B6E5] DEVICEINITSUCCESS = VTD
[0002B6E5] DEVICEINIT = VXDLDR
[0002B70B] DEVICEINITSUCCESS = VXDLDR
[0002B710] Dynamic load device isapnp.vxd
[0002B71D] Dynamic init device ISAPNP
[0002B71D] Dynamic init success ISAPNP
[0002B71D] Dynamic load success isapnp.vxd
[0002B71D] Dynamic load device mmdevldr.vxd
[0002B72E] Dynamic init device MMDEVLDR
[0002B72E] Dynamic init success MMDEVLDR
[0002B72F] Dynamic load success mmdevldr.vxd
[0002B72F] Dynamic load device vjoyd.vxd
[0002B734] Dynamic init device VJOYD
[0002B734] Dynamic init success VJOYD
[0002B734] Dynamic load success vjoyd.vxd
[0002B734] Dynamic load device mmdevldr.vxd
[0002B738] Dynamic load success mmdevldr.vxd
[0002B738] Dynamic load device msmpu401.vxd
[0002B73C] Dynamic init device MSMPUVXD
[0002B73C] Dynamic init success MSMPUVXD
[0002B73C] Dynamic load success msmpu401.vxd
[0002B73C] DEVICEINIT = CONFIGMG
[0002B73D] DEVICEINITSUCCESS = CONFIGMG
[0002B73E] DEVICEINIT = VCDFSD
[0002B73E] DEVICEINITSUCCESS = VCDFSD
[0002B73E] DEVICEINIT = IOS
[0002B751] Dynamic load device C:\WINDOWS\system\IOSUBSYS\apix.vxd
[0002B752] Dynamic load success C:\WINDOWS\system\IOSUBSYS\apix.vxd
[0002B754] Dynamic load device C:\WINDOWS\system\IOSUBSYS\cdfs.vxd
[0002B755] Dynamic load success C:\WINDOWS\system\IOSUBSYS\cdfs.vxd
[0002B755] Dynamic load device C:\WINDOWS\system\IOSUBSYS\cdtsd.vxd
[0002B756] Dynamic load success C:\WINDOWS\system\IOSUBSYS\cdtsd.vxd
[0002B757] Dynamic load device C:\WINDOWS\system\IOSUBSYS\cdvsd.vxd
[0002B758] Dynamic load success C:\WINDOWS\system\IOSUBSYS\cdvsd.vxd
[0002B758] Dynamic load device C:\WINDOWS\system\IOSUBSYS\disktsd.vxd
[0002B759] Dynamic load success C:\WINDOWS\system\IOSUBSYS\disktsd.vxd
[0002B759] Dynamic load device C:\WINDOWS\system\IOSUBSYS\diskvsd.vxd
[0002B75A] Dynamic load success C:\WINDOWS\system\IOSUBSYS\diskvsd.vxd
[0002B75A] Dynamic load device C:\WINDOWS\system\IOSUBSYS\voltrack.vxd
[0002B75C] Dynamic load success C:\WINDOWS\system\IOSUBSYS\voltrack.vxd
[0002B75C] Dynamic load device C:\WINDOWS\system\IOSUBSYS\necatapi.vxd
[0002B75D] Dynamic load success C:\WINDOWS\system\IOSUBSYS\necatapi.vxd
[0002B75D] Dynamic load device C:\WINDOWS\system\IOSUBSYS\scsi1hlp.vxd
[0002B75E] Dynamic load success C:\WINDOWS\system\IOSUBSYS\scsi1hlp.vxd
[0002B75E] Dynamic load device C:\WINDOWS\system\IOSUBSYS\drvspacx.vxd
[0002B761] Dynamic load success C:\WINDOWS\system\IOSUBSYS\drvspacx.vxd
[0002B761] Dynamic load device C:\WINDOWS\system\IOSUBSYS\rmm.pdr
[0002B762] Dynamic load success C:\WINDOWS\system\IOSUBSYS\rmm.pdr
[0002B763] DEVICEINITSUCCESS = IOS
[0002B764] DEVICEINIT = PAGEFILE
[0002B765] DEVICEINITSUCCESS = PAGEFILE
[0002B765] DEVICEINIT = PAGESWAP
[0002B765] DEVICEINITSUCCESS = PAGESWAP
[0002B765] DEVICEINIT = PARITY
[0002B765] DEVICEINITSUCCESS = PARITY
[0002B766] DEVICEINIT = REBOOT
[0002B766] DEVICEINITSUCCESS = REBOOT
[0002B766] DEVICEINIT = EBIOS
[0002B766] DEVICEINITSUCCESS = EBIOS
[0002B766] DEVICEINIT = VDD
[0002B76D] DEVICEINITSUCCESS = VDD
[0002B76E] DEVICEINIT = VSD
[0002B76E] DEVICEINITSUCCESS = VSD
[0002B76E] DEVICEINIT = COMBUFF
[0002B76E] DEVICEINITSUCCESS = COMBUFF
[0002B76F] DEVICEINIT = VCD
[0002B76F] DEVICEINITSUCCESS = VCD
[0002B770] DEVICEINIT = VMOUSE
[0002B770] DEVICEINITSUCCESS = VMOUSE
[0002B770] DEVICEINIT = MSMINI
[0002B773] DEVICEINITSUCCESS = MSMINI
[0002B773] DEVICEINIT = VKD
[0002B773] DEVICEINITSUCCESS = VKD
[0002B773] DEVICEINIT = ENABLE
[0002B774] DEVICEINITSUCCESS = ENABLE
[0002B774] DEVICEINIT = VPD
[0002B774] DEVICEINITSUCCESS = VPD
[0002B774] DEVICEINIT = INT13
[0002B775] DEVICEINITSUCCESS = INT13
[0002B775] DEVICEINIT = VMCPD
[0002B775] DEVICEINITSUCCESS = VMCPD
[0002B775] DEVICEINIT = BIOSXLAT
[0002B775] DEVICEINITSUCCESS = BIOSXLAT
[0002B776] DEVICEINIT = DOSMGR
[0002B776] DEVICEINITSUCCESS = DOSMGR
[0002B776] DEVICEINIT = VSHARE
[0002B777] DEVICEINITSUCCESS = VSHARE
[0002B777] DEVICEINIT = VMPOLL
[0002B778] DEVICEINITSUCCESS = VMPOLL
[0002B778] DEVICEINIT = VWIN32
[0002B778] DEVICEINITSUCCESS = VWIN32
[0002B779] DEVICEINIT = VCOMM
[0002B779] DEVICEINITSUCCESS = VCOMM
[0002B779] DEVICEINIT = VCOND
[0002B779] DEVICEINITSUCCESS = VCOND
[0002B77A] DEVICEINIT = VTDAPI
[0002B77A] DEVICEINITSUCCESS = VTDAPI
[0002B77A] DEVICEINIT = VFLATD
[0002B77A] DEVICEINITSUCCESS = VFLATD
[0002B77A] DEVICEINIT = VDMAD
[0002B77B] DEVICEINITSUCCESS = VDMAD
[0002B77B] DEVICEINIT = V86MMGR
[0002B77C] DEVICEINITSUCCESS = V86MMGR
[0002B77C] DEVICEINIT = SPOOLER
[0002B77D] DEVICEINITSUCCESS = SPOOLER
[0002B77D] DEVICEINIT = VFAT
[0002B77D] DEVICEINITSUCCESS = VFAT
[0002B77E] DEVICEINIT = VDEF
[0002B77E] DEVICEINITSUCCESS = VDEF
[0002B781] Initing hsflop.pdr
[0002B7D9] Init Success hsflop.pdr
[0002B7DD] Initing esdi_506.pdr
[0002B886] Init Success esdi_506.pdr
[0002B887] Initing esdi_506.pdr
[0002B888] Init Success esdi_506.pdr
[0002B8A3] INITCOMPLETE = VMM
[0002B8A3] INITCOMPLETESUCCESS = VMM
[0002B8A3] INITCOMPLETE = VCACHE
[0002B8A3] INITCOMPLETESUCCESS = VCACHE
[0002B8A3] INITCOMPLETE = PERF
[0002B8A4] INITCOMPLETESUCCESS = PERF
[0002B8A4] INITCOMPLETE = VPICD
[0002B8A4] INITCOMPLETESUCCESS = VPICD
[0002B8A4] INITCOMPLETE = VTD
[0002B8A4] INITCOMPLETESUCCESS = VTD
[0002B8A4] INITCOMPLETE = VXDLDR
[0002B8A4] INITCOMPLETESUCCESS = VXDLDR
[0002B8A4] INITCOMPLETE = ISAPNP
[0002B8A4] INITCOMPLETESUCCESS = ISAPNP
[0002B8A4] INITCOMPLETE = CONFIGMG
[0002B8A5] INITCOMPLETESUCCESS = CONFIGMG
[0002B8AD] INITCOMPLETE = VCDFSD
[0002B8AD] INITCOMPLETESUCCESS = VCDFSD
[0002B8AE] INITCOMPLETE = IOS
[0002B8C4] INITCOMPLETESUCCESS = IOS
[0002B8C4] INITCOMPLETE = PAGEFILE
[0002B8C4] INITCOMPLETESUCCESS = PAGEFILE
[0002B8C5] INITCOMPLETE = PAGESWAP
[0002B8C5] INITCOMPLETESUCCESS = PAGESWAP
[0002B8C5] INITCOMPLETE = PARITY
[0002B8C5] INITCOMPLETESUCCESS = PARITY
[0002B8C5] INITCOMPLETE = REBOOT
[0002B8C5] INITCOMPLETESUCCESS = REBOOT
[0002B8C5] INITCOMPLETE = EBIOS
[0002B8C5] INITCOMPLETESUCCESS = EBIOS
[0002B8C5] INITCOMPLETE = VDD
[0002B8C5] INITCOMPLETESUCCESS = VDD
[0002B8C6] INITCOMPLETE = VSD
[0002B8C6] INITCOMPLETESUCCESS = VSD
[0002B8C6] INITCOMPLETE = COMBUFF
[0002B8C6] INITCOMPLETESUCCESS = COMBUFF
[0002B8C6] INITCOMPLETE = VCD
[0002B8C6] INITCOMPLETESUCCESS = VCD
[0002B8C6] INITCOMPLETE = VMOUSE
[0002B8C6] INITCOMPLETESUCCESS = VMOUSE
[0002B8C7] INITCOMPLETE = MSMINI
[0002B8C7] INITCOMPLETESUCCESS = MSMINI
[0002B8C7] INITCOMPLETE = VKD
[0002B8C8] INITCOMPLETESUCCESS = VKD
[0002B8C8] INITCOMPLETE = ENABLE
[0002B8C8] INITCOMPLETESUCCESS = ENABLE
[0002B8C8] INITCOMPLETE = VPD
[0002B8C9] INITCOMPLETESUCCESS = VPD
[0002B8C9] INITCOMPLETE = INT13
[0002B8CA] INITCOMPLETESUCCESS = INT13
[0002B8CA] INITCOMPLETE = VMCPD
[0002B8CA] INITCOMPLETESUCCESS = VMCPD
[0002B8CA] INITCOMPLETE = BIOSXLAT
[0002B8CA] INITCOMPLETESUCCESS = BIOSXLAT
[0002B8CA] INITCOMPLETE = DOSMGR
[0002B8CE] INITCOMPLETESUCCESS = DOSMGR
[0002B8CE] INITCOMPLETE = VSHARE
[0002B8CE] INITCOMPLETESUCCESS = VSHARE
[0002B8CE] INITCOMPLETE = VMPOLL
[0002B8CE] INITCOMPLETESUCCESS = VMPOLL
[0002B8CF] INITCOMPLETE = VWIN32
[0002B8D0] INITCOMPLETESUCCESS = VWIN32
[0002B8D0] INITCOMPLETE = VCOMM
[0002B8D0] Dynamic load device serenum.vxd
[0002B8D3] Dynamic init device SERENUM
[0002B8D3] Dynamic init success SERENUM
[0002B8D3] Dynamic load success serenum.vxd
[0002B8D3] Dynamic load device serenum.vxd
[0002B8D6] Dynamic load success serenum.vxd
[0002B8D6] Dynamic load device lptenum.vxd
[0002B8DA] Dynamic init device LPTENUM
[0002B8DA] Dynamic init success LPTENUM
[0002B8DA] Dynamic load success lptenum.vxd
[0002B8DA] INITCOMPLETESUCCESS = VCOMM
[0002B8DA] Dynamic load device C:\WINDOWS\system\serial.vxd
[0002B8DC] Dynamic init device SERIAL
[0002B8DC] Dynamic init success SERIAL
[0002B8DC] Dynamic load success C:\WINDOWS\system\serial.vxd
[0002B8E1] INITCOMPLETE = VCOND
[0002B8E2] INITCOMPLETESUCCESS = VCOND
[0002B8E2] INITCOMPLETE = VTDAPI
[0002B8E2] INITCOMPLETESUCCESS = VTDAPI
[0002B8E2] INITCOMPLETE = VFLATD
[0002B8E2] INITCOMPLETESUCCESS = VFLATD
[0002B8E2] INITCOMPLETE = mmdevldr
[0002B8E2] INITCOMPLETESUCCESS = mmdevldr
[0002B8E2] INITCOMPLETE = vjoyd
[0002B8E2] INITCOMPLETESUCCESS = vjoyd
[0002B8E3] INITCOMPLETE = msmpu401
[0002B8E3] INITCOMPLETESUCCESS = msmpu401
[0002B8E3] INITCOMPLETE = DiskTSD
[0002B8E3] INITCOMPLETESUCCESS = DiskTSD
[0002B8E3] INITCOMPLETE = voltrack
[0002B8E3] INITCOMPLETESUCCESS = voltrack
[0002B8E3] INITCOMPLETE = HSFLOP
[0002B8E3] INITCOMPLETESUCCESS = HSFLOP
[0002B8E3] INITCOMPLETE = ESDI_506
[0002B8E3] INITCOMPLETESUCCESS = ESDI_506
[0002B8E4] INITCOMPLETE = SERENUM
[0002B8E4] INITCOMPLETESUCCESS = SERENUM
[0002B8E4] INITCOMPLETE = LPTENUM
[0002B8E4] INITCOMPLETESUCCESS = LPTENUM
[0002B8E4] INITCOMPLETE = VDMAD
[0002B8E4] INITCOMPLETESUCCESS = VDMAD
[0002B8E5] INITCOMPLETE = V86MMGR
[0002B8E5] INITCOMPLETESUCCESS = V86MMGR
[0002B8E6] INITCOMPLETE = SPOOLER
[0002B8E6] INITCOMPLETESUCCESS = SPOOLER
[0002B8E6] INITCOMPLETE = VFAT
[0002B8E6] INITCOMPLETESUCCESS = VFAT
[0002B8ED] INITCOMPLETE = VDEF
[0002B8ED] INITCOMPLETESUCCESS = VDEF
[0002B8ED] INITCOMPLETE = IFSMGR
[0002B8ED] INITCOMPLETESUCCESS = IFSMGR
[0002B8EE] INITCOMPLETE = VFBACKUP
[0002B8EE] INITCOMPLETESUCCESS = VFBACKUP
[0002B8EE] INITCOMPLETE = SHELL
[0002B8EE] INITCOMPLETESUCCESS = SHELL
Initializing KERNEL
LoadStart = system.drv
LoadSuccess = system.drv
LoadStart = keyboard.drv
LoadSuccess = keyboard.drv
LoadStart = mouse.drv
LoadSuccess = mouse.drv
LoadStart = vga.drv
LoadSuccess = vga.drv
LoadStart = mmsound.drv
LoadSuccess = mmsound.drv
LoadStart = comm.drv
LoadSuccess = comm.drv
LoadStart = gdi.exe
LoadStart = C:\WINDOWS\SYSTEM\GDI32.DLL
LoadStart = GDI.EXE
LoadSuccess = GDI.EXE
LoadStart = GDI.EXE
LoadSuccess = GDI.EXE
LoadStart = GDI.EXE
LoadSuccess = GDI.EXE
LoadStart = GDI.EXE
LoadSuccess = GDI.EXE
LoadSuccess = C:\WINDOWS\SYSTEM\GDI32.DLL
LoadStart = C:\WINDOWS\fonts\vgasys.fon
LoadSuccess = C:\WINDOWS\fonts\vgasys.fon
LoadStart = C:\WINDOWS\fonts\vgafix.fon
LoadSuccess = C:\WINDOWS\fonts\vgafix.fon
LoadStart = C:\WINDOWS\fonts\vgaoem.fon
LoadSuccess = C:\WINDOWS\fonts\vgaoem.fon
LoadSuccess = gdi.exe
LoadStart = user.exe
LoadStart = DDEML.DLL
LoadSuccess = DDEML.DLL
LoadStart = C:\WINDOWS\SYSTEM\USER32.DLL
LoadStart = USER.EXE
LoadSuccess = USER.EXE
LoadStart = USER.EXE
LoadSuccess = USER.EXE
LoadStart = USER.EXE
LoadSuccess = USER.EXE
LoadStart = USER.EXE
LoadSuccess = USER.EXE
LoadStart = USER.EXE
LoadSuccess = USER.EXE
LoadSuccess = C:\WINDOWS\SYSTEM\USER32.DLL
Init = KEYBOARD
InitDone = KEYBOARD
Init = Mouse
Status = Mouse driver installed
InitDone = Mouse
Init = DISPLAY
LoadStart = DISPLAY.drv
LoadSuccess = DISPLAY.drv
InitDone = DISPLAY
Init = Display Resources
InitDone = Display Resources
LoadStart = C:\WINDOWS\fonts\MARLETT.TTF
LoadFail = C:\WINDOWS\fonts\MARLETT.TTF Failure code is 0016

LoadStart = C:\WINDOWS\fonts\serife.fon
LoadSuccess = C:\WINDOWS\fonts\serife.fon
LoadStart = C:\WINDOWS\fonts\sserife.fon
LoadSuccess = C:\WINDOWS\fonts\sserife.fon
LoadStart = C:\WINDOWS\fonts\coure.fon
LoadSuccess = C:\WINDOWS\fonts\coure.fon
LoadStart = C:\WINDOWS\fonts\symbole.fon
LoadSuccess = C:\WINDOWS\fonts\symbole.fon
LoadStart = C:\WINDOWS\fonts\smalle.fon
LoadSuccess = C:\WINDOWS\fonts\smalle.fon
LoadSuccess = user.exe
LoadStart = MSGSRV32.EXE
LoadSuccess = MSGSRV32.EXE
Init = Final USER
InitDone = Final USER
Init = Installable Drivers
InitDone = Installable Drivers
Init = TSRQuery
InitDone = TSRQuery
1182-Windows 95_setupcontinuing.jpg
Filename
1182-Windows 95_setupcontinuing.jpg
File size
155.18 KiB
Views
1357 views
File comment
Setup continuing now...
File license
Fair use/fair dealing exception
1183-Windows 95_setupsettingupcontrolpanel.jpg
Filename
1183-Windows 95_setupsettingupcontrolpanel.jpg
File size
154.31 KiB
Views
1357 views
File comment
Setting up control panel...
File license
Fair use/fair dealing exception
1184-Windows 95_setupstartmenushortcuts.jpg
Filename
1184-Windows 95_setupstartmenushortcuts.jpg
File size
154.64 KiB
Views
1357 views
File comment
Creating Start Menu shortcuts...
File license
Fair use/fair dealing exception
1185-Windows 95_setuppreparinghelpforfirstuse.jpg
Filename
1185-Windows 95_setuppreparinghelpforfirstuse.jpg
File size
150.03 KiB
Views
1357 views
File comment
Preparing help for first use...
File license
Fair use/fair dealing exception

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 13 of 45, by superfury

User metadata
Rank l33t++
Rank
l33t++
1186-Windows 95_setuptimezone.jpg
Filename
1186-Windows 95_setuptimezone.jpg
File size
143.86 KiB
Views
1357 views
File comment
Timezone... Check!
File license
Fair use/fair dealing exception
1187-Use exchange or not.jpg
Filename
1187-Use exchange or not.jpg
File size
127.58 KiB
Views
1357 views
File comment
Using exchange? Nope!
File license
Fair use/fair dealing exception
1188-Finalizing settings.jpg
Filename
1188-Finalizing settings.jpg
File size
16.99 KiB
Views
1357 views
File comment
Finalizing settings...
File license
Fair use/fair dealing exception

Yay! It's fully booting!!! 😁:D:D:D:D:D

1190-First Windows 95 desktop in UniPCemu.jpg
Filename
1190-First Windows 95 desktop in UniPCemu.jpg
File size
91.99 KiB
Views
1357 views
File comment
First time Windows 95 booting and running in UniPCemu!!!
File license
Fair use/fair dealing exception
1191-General system properties.jpg
Filename
1191-General system properties.jpg
File size
54.92 KiB
Views
1357 views
File comment
General system properties UniPCemu maxed out RAM.
File license
Fair use/fair dealing exception

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 14 of 45, by superfury

User metadata
Rank l33t++
Rank
l33t++
1192-Cant tell me about the soundblaster properties.jpg
Filename
1192-Cant tell me about the soundblaster properties.jpg
File size
94.64 KiB
Views
1357 views
File comment
Can't tell me about the Sound Blaster not working correctly?
File license
Fair use/fair dealing exception

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 15 of 45, by superfury

User metadata
Rank l33t++
Rank
l33t++

Errrr.... Tried accessing a simple 1.44MB floppy(although the BIOS uses 720K settings)...

1193-Accessing the floppy disk makes it shutdown unexpectedly.jpg
Filename
1193-Accessing the floppy disk makes it shutdown unexpectedly.jpg
File size
16.89 KiB
Views
1355 views
File comment
Using the floppy disk makes it shut down unexpectedly?
File license
Fair use/fair dealing exception

That's an instant 'crash' to an unresponsive shutdown logo screen?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 16 of 45, by superfury

User metadata
Rank l33t++
Rank
l33t++

Just tried shutting down Windows 95A and typing "mode co80<enter>". Drops back to the MS-DOS prompt just like that. Apparently this works properly too! 🤣

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 17 of 45, by superfury

User metadata
Rank l33t++
Rank
l33t++

One strange thing, though: the CD-ROM drives aren't recognized after installing? Does it need extra settings or files for those?

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 18 of 45, by superfury

User metadata
Rank l33t++
Rank
l33t++

Ran it with 12MB RAM. Eventually crashed the 95A into a BSOD on VMM.VXD.

Now trying to reinstall the whole thing(might help fix some problems) by fixing corrupted files.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 19 of 45, by danoon

User metadata
Rank Member
Rank
Member
superfury wrote:

Ran it with 12MB RAM. Eventually crashed the 95A into a BSOD on VMM.VXD.

Now trying to reinstall the whole thing(might help fix some problems) by fixing corrupted files.

Corrupt file system in Windows 95, that brings back memory. I remember running Visual Studio and developing code on Windows 95. I will never forget loosing work with that combination. It was easy to crash the OS and sometimes if a file was open when it crashed the file would get truncated to 0.

http://www.boxedwine.org/