Cleaned up segment zeroing rules and added Windows 95 debugger configuration
This commit is contained in:
parent
7cd2e3a5e6
commit
f94467168d
12 changed files with 2424 additions and 2320 deletions
|
|
@ -12,4 +12,4 @@ COMPAQ DeskPro 386 Machines
|
|||
* [COMPAQ DeskPro 386 with 2Mb RAM and COMPAQ VGA (Debugger)](other/2048kb/debugger/),([Backtrack](other/2048kb/debugger/backtrack/))
|
||||
* [COMPAQ DeskPro 386 with 2Mb RAM and IBM VGA](vga/2048kb/) ([Debugger](vga/2048kb/debugger/))
|
||||
* [COMPAQ DeskPro 386 with 4Mb RAM and IBM VGA](vga/4096kb/) ([Debugger](vga/4096kb/debugger/))
|
||||
* [COMPAQ DeskPro 386 with 4Mb RAM and IBM VGA running Windows 95](/disks/pc/windows/win95/4.00.950/)
|
||||
* [COMPAQ DeskPro 386 with 4Mb RAM and IBM VGA running Windows 95](/disks/pc/windows/win95/4.00.950/) ([Debugger](/disks/pc/windows/win95/4.00.950/debugger/))
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ Windows 95 was released to manufacturing on July 14, 1995 and went on sale at mi
|
|||
|
||||
It is shown running below, following a "Compact Installation" on a 68Mb hard disk. Before the machine can
|
||||
start, it must download the disk image, which may take a minute or two, depending on the speed of your
|
||||
internet connection.
|
||||
internet connection. You can also run Windows 95 with the [PCjs Debugger](debugger/).
|
||||
|
||||
More information about this Windows 95 demo is available in the [PCjs Blog](/blog/2015/09/21/).
|
||||
|
||||
|
|
|
|||
24
disks/pc/windows/win95/4.00.950/debugger/README.md
Normal file
24
disks/pc/windows/win95/4.00.950/debugger/README.md
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
layout: page
|
||||
title: "Microsoft Windows 95 (First Retail Release) with Debugger"
|
||||
permalink: /disks/pc/windows/win95/4.00.950/debugger/
|
||||
machines:
|
||||
- type: pc
|
||||
id: deskpro386
|
||||
debugger: true
|
||||
state: /disks/pc/windows/win95/4.00.950/deskpro386.json
|
||||
config: /devices/pc/machine/compaq/deskpro386/vga/4096kb/debugger/machine.xml
|
||||
drives: '[{name:"68Mb Hard Disk",type:4,path:"http://archive.pcjs.org/disks/pc/fixed/68mb/win95.json"}]'
|
||||
autoMount: ''
|
||||
---
|
||||
|
||||
Microsoft Windows 95 (First Retail Release) with Debugger
|
||||
---
|
||||
|
||||
Windows 95 is shown running below, following a "Compact Installation" on a 68Mb hard disk. Before the machine can
|
||||
start, it must download the disk image, which may take a minute or two, depending on the speed of your
|
||||
internet connection. You can also run [Windows 95](../) without the PCjs Debugger.
|
||||
|
||||
More information about this Windows 95 demo is available in the [PCjs Blog](/blog/2015/09/21/).
|
||||
|
||||
{% include machine.html id="deskpro386" %}
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -99,10 +99,10 @@ var DbgAddr;
|
|||
* How do you figure out where the code for GlobalAlloc is in the first place? You need to have
|
||||
* BACKTRACK support enabled (which currently means running the non-COMPILED version), so that as
|
||||
* the Disk component loads disk images, it will automatically extract symbolic information from all
|
||||
* "NE" (New Executable) binaries on those disks, which the Debugger's "di" command can then search
|
||||
* "NE" (New Executable) binaries on those disks, which the Debugger's "dt" command can then search
|
||||
* for you; eg:
|
||||
*
|
||||
* ## di globalalloc
|
||||
* ## dt globalalloc
|
||||
* GLOBALALLOC: KRNL386.EXE 0001:022B len 0xC570
|
||||
*
|
||||
* And then you just need to do a bit more sleuthing to find the right CODE segment. And that just
|
||||
|
|
@ -1506,10 +1506,10 @@ if (DEBUGGER) {
|
|||
}
|
||||
|
||||
this.messageDump(Messages.BUS, function onDumpBus(asArgs) { dbg.dumpBus(asArgs); });
|
||||
this.messageDump(Messages.MEM, function onDumpMem(asArgs) { dbg.dumpMem(asArgs); });
|
||||
this.messageDump(Messages.DESC, function onDumpSel(asArgs) { dbg.dumpSel(asArgs); });
|
||||
this.messageDump(Messages.TSS, function onDumpTSS(asArgs) { dbg.dumpTSS(asArgs); });
|
||||
this.messageDump(Messages.DOS, function onDumpDOS(asArgs) { dbg.dumpDOS(asArgs); });
|
||||
this.messageDump(Messages.MEM, function onDumpMem(asArgs) { dbg.dumpMem(asArgs); });
|
||||
this.messageDump(Messages.TSS, function onDumpTSS(asArgs) { dbg.dumpTSS(asArgs); });
|
||||
|
||||
if (Interrupts.WINDBG.ENABLED || Interrupts.WINDBGRM.ENABLED) {
|
||||
this.fWinDbg = null;
|
||||
|
|
@ -2763,36 +2763,44 @@ if (DEBUGGER) {
|
|||
};
|
||||
|
||||
/**
|
||||
* dumpDOS(asArgs)
|
||||
*
|
||||
* Dumps DOS MCBs (Memory Control Blocks).
|
||||
*
|
||||
* TODO: Add some code to detect the current version of DOS (if any) and locate the first MCB automatically.
|
||||
* dumpBackTrack(asArgs)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {Array.<string>} asArgs
|
||||
*/
|
||||
Debugger.prototype.dumpDOS = function(asArgs)
|
||||
Debugger.prototype.dumpBackTrack = function(asArgs)
|
||||
{
|
||||
var mcb;
|
||||
var sMCB = asArgs[0];
|
||||
if (sMCB) {
|
||||
mcb = this.parseValue(sMCB);
|
||||
}
|
||||
if (mcb === undefined) {
|
||||
this.println("invalid MCB");
|
||||
return;
|
||||
}
|
||||
this.println("dumpMCB(" + str.toHexWord(mcb) + ')');
|
||||
while (mcb) {
|
||||
var dbgAddr = this.newAddr(0, mcb);
|
||||
var bSig = this.getByte(dbgAddr, 1);
|
||||
var wPID = this.getShort(dbgAddr, 2);
|
||||
var wParas = this.getShort(dbgAddr, 5);
|
||||
if (bSig != 0x4D && bSig != 0x5A) break;
|
||||
this.println(this.toHexOffset(0, mcb) + ": '" + String.fromCharCode(bSig) + "' PID=" + str.toHexWord(wPID) + " LEN=" + str.toHexWord(wParas) + ' "' + this.getSZ(dbgAddr, 8) + '"');
|
||||
mcb += 1 + wParas;
|
||||
var sInfo = "no information";
|
||||
if (BACKTRACK) {
|
||||
var sAddr = asArgs[0];
|
||||
var dbgAddr = this.parseAddr(sAddr, true, true, false);
|
||||
if (dbgAddr) {
|
||||
var addr = this.getAddr(dbgAddr);
|
||||
if (dbgAddr.type != Debugger.ADDRTYPE.PHYSICAL) {
|
||||
var pageInfo = this.getPageInfo(addr);
|
||||
if (pageInfo) {
|
||||
dbgAddr.addr = pageInfo.addrPhys;
|
||||
dbgAddr.type = Debugger.ADDRTYPE.PHYSICAL;
|
||||
}
|
||||
}
|
||||
sInfo = this.toHexAddr(dbgAddr) + ": " + (this.bus.getSymbol(addr, true) || sInfo);
|
||||
} else {
|
||||
var component, componentPrev = null;
|
||||
while (component = this.cmp.getMachineComponent("Disk", componentPrev)) {
|
||||
var aInfo = component.getSymbolInfo(sAddr);
|
||||
if (aInfo.length) {
|
||||
sInfo = "";
|
||||
for (var i in aInfo) {
|
||||
var a = aInfo[i];
|
||||
if (sInfo) sInfo += '\n';
|
||||
sInfo += a[0] + ": " + a[1] + ' ' + str.toHex(a[2], 4) + ':' + str.toHex(a[3], 4) + " len " + str.toHexWord(a[4]);
|
||||
}
|
||||
}
|
||||
componentPrev = component;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sInfo;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -2871,6 +2879,78 @@ if (DEBUGGER) {
|
|||
this.dumpBlocks(this.cpu.aBusBlocks, asArgs[0]);
|
||||
};
|
||||
|
||||
/**
|
||||
* dumpDOS(asArgs)
|
||||
*
|
||||
* Dumps DOS MCBs (Memory Control Blocks).
|
||||
*
|
||||
* TODO: Add some code to detect the current version of DOS (if any) and locate the first MCB automatically.
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {Array.<string>} asArgs
|
||||
*/
|
||||
Debugger.prototype.dumpDOS = function(asArgs)
|
||||
{
|
||||
var mcb;
|
||||
var sMCB = asArgs[0];
|
||||
if (sMCB) {
|
||||
mcb = this.parseValue(sMCB);
|
||||
}
|
||||
if (mcb === undefined) {
|
||||
this.println("invalid MCB");
|
||||
return;
|
||||
}
|
||||
this.println("dumpMCB(" + str.toHexWord(mcb) + ')');
|
||||
while (mcb) {
|
||||
var dbgAddr = this.newAddr(0, mcb);
|
||||
var bSig = this.getByte(dbgAddr, 1);
|
||||
var wPID = this.getShort(dbgAddr, 2);
|
||||
var wParas = this.getShort(dbgAddr, 5);
|
||||
if (bSig != 0x4D && bSig != 0x5A) break;
|
||||
this.println(this.toHexOffset(0, mcb) + ": '" + String.fromCharCode(bSig) + "' PID=" + str.toHexWord(wPID) + " LEN=" + str.toHexWord(wParas) + ' "' + this.getSZ(dbgAddr, 8) + '"');
|
||||
mcb += 1 + wParas;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* dumpIDT(asArgs)
|
||||
*
|
||||
* Dumps an IDT vector entry.
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {Array.<string>} asArgs
|
||||
*/
|
||||
Debugger.prototype.dumpIDT = function(asArgs)
|
||||
{
|
||||
var sIDT = asArgs[0];
|
||||
|
||||
if (!sIDT) {
|
||||
this.println("no IDT vector");
|
||||
return;
|
||||
}
|
||||
|
||||
var nIDT = this.parseValue(sIDT);
|
||||
if (nIDT === undefined || nIDT < 0 || nIDT > 255) {
|
||||
this.println("invalid vector: " + sIDT);
|
||||
return;
|
||||
}
|
||||
|
||||
var ch = '&', fProt = this.cpu.getProtMode(), fAddr32 = false;
|
||||
var addrIDT = this.cpu.addrIDT + (nIDT << (fProt? 3 : 2));
|
||||
var off = this.cpu.getShort(addrIDT + X86.DESC.LIMIT.OFFSET);
|
||||
var sel = this.cpu.getShort(addrIDT + X86.DESC.BASE.OFFSET);
|
||||
if (fProt) {
|
||||
ch = '#';
|
||||
var acc = this.cpu.getShort(addrIDT + X86.DESC.ACC.OFFSET);
|
||||
if (acc & X86.DESC.ACC.TYPE.NONSEG_386) {
|
||||
fAddr32 = true;
|
||||
off |= this.cpu.getShort(addrIDT + X86.DESC.EXT.OFFSET) << 16;
|
||||
}
|
||||
}
|
||||
|
||||
this.println("dumpIDT(" + str.toHexWord(nIDT) + "): " + ch + str.toHex(sel, 4) + ':' + str.toHex(off, fAddr32? 8 : 4));
|
||||
};
|
||||
|
||||
/**
|
||||
* dumpMem(asArgs)
|
||||
*
|
||||
|
|
@ -2934,47 +3014,6 @@ if (DEBUGGER) {
|
|||
return pageInfo;
|
||||
};
|
||||
|
||||
/**
|
||||
* dumpInfo(asArgs)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {Array.<string>} asArgs
|
||||
*/
|
||||
Debugger.prototype.dumpInfo = function(asArgs)
|
||||
{
|
||||
var sInfo = "no information";
|
||||
if (BACKTRACK) {
|
||||
var sAddr = asArgs[0];
|
||||
var dbgAddr = this.parseAddr(sAddr, true, true, false);
|
||||
if (dbgAddr) {
|
||||
var addr = this.getAddr(dbgAddr);
|
||||
if (dbgAddr.type != Debugger.ADDRTYPE.PHYSICAL) {
|
||||
var pageInfo = this.getPageInfo(addr);
|
||||
if (pageInfo) {
|
||||
dbgAddr.addr = pageInfo.addrPhys;
|
||||
dbgAddr.type = Debugger.ADDRTYPE.PHYSICAL;
|
||||
}
|
||||
}
|
||||
sInfo = this.toHexAddr(dbgAddr) + ": " + (this.bus.getSymbol(addr, true) || sInfo);
|
||||
} else {
|
||||
var component, componentPrev = null;
|
||||
while (component = this.cmp.getMachineComponent("Disk", componentPrev)) {
|
||||
var aInfo = component.getSymbolInfo(sAddr);
|
||||
if (aInfo.length) {
|
||||
sInfo = "";
|
||||
for (var i in aInfo) {
|
||||
var a = aInfo[i];
|
||||
if (sInfo) sInfo += '\n';
|
||||
sInfo += a[0] + ": " + a[1] + ' ' + str.toHex(a[2], 4) + ':' + str.toHex(a[3], 4) + " len " + str.toHexWord(a[4]);
|
||||
}
|
||||
}
|
||||
componentPrev = component;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sInfo;
|
||||
};
|
||||
|
||||
/**
|
||||
* dumpPage(asArgs)
|
||||
*
|
||||
|
|
@ -6376,10 +6415,11 @@ if (DEBUGGER) {
|
|||
this.println("\tdw [a] [#] dump # words at address a");
|
||||
this.println("\tdd [a] [#] dump # dwords at address a");
|
||||
this.println("\tdh [#] [#] dump # instructions from history");
|
||||
if (BACKTRACK) {
|
||||
this.println("\tdi [a] dump backtrack info for address a");
|
||||
}
|
||||
this.println("\tdi [#] dump descriptor info for IDT #");
|
||||
this.println("\tds [#] dump descriptor info for selector #");
|
||||
if (BACKTRACK) {
|
||||
this.println("\tdt [a] dump backtrack info for address a");
|
||||
}
|
||||
if (sDumpers.length) this.println("dump extension commands:\n\t" + sDumpers);
|
||||
return;
|
||||
}
|
||||
|
|
@ -6470,7 +6510,13 @@ if (DEBUGGER) {
|
|||
|
||||
if (sCmd == "di") {
|
||||
asArgs.shift();
|
||||
var sInfo = this.dumpInfo(asArgs);
|
||||
this.dumpIDT(asArgs);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sCmd == "dt") {
|
||||
asArgs.shift();
|
||||
var sInfo = this.dumpBackTrack(asArgs);
|
||||
this.println(sInfo);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -240,9 +240,10 @@ var X86 = {
|
|||
GATE386_CALL: 0x0C00, // 80386 and up
|
||||
GATE386_INT: 0x0E00, // 80386 and up
|
||||
GATE386_TRAP: 0x0F00, // 80386 and up
|
||||
CODE_OR_DATA: 0x1E00,
|
||||
DATA_READONLY: 0x1000,
|
||||
DATA_WRITABLE: 0x1200,
|
||||
DATA_EXPDOWN_READONLY: 0x1400,
|
||||
DATA_EXPDOWN: 0x1400,
|
||||
DATA_EXPDOWN_WRITABLE: 0x1600,
|
||||
CODE_EXECONLY: 0x1800,
|
||||
CODE_READABLE: 0x1A00,
|
||||
|
|
|
|||
|
|
@ -1084,7 +1084,8 @@ X86CPU.prototype.resetRegs = function()
|
|||
* of accessing or changing them, so this is an implementation detail those processors are unaware of.
|
||||
*/
|
||||
this.regCR0 = X86.CR0.MSW.ON;
|
||||
this.addrIDT = 0; this.addrIDTLimit = 0x03FF;
|
||||
this.addrIDT = 0;
|
||||
this.addrIDTLimit = 0x03FF;
|
||||
this.regPS = this.nIOPL = 0;// these should be set before the first setPS() call
|
||||
|
||||
/*
|
||||
|
|
@ -1275,21 +1276,6 @@ X86CPU.prototype.resetRegs = function()
|
|||
this.setProtMode();
|
||||
};
|
||||
|
||||
/**
|
||||
* zeroSeg(seg)
|
||||
*
|
||||
* Helper to zero a segment register as privilege transitions require.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {X86Seg} seg
|
||||
*/
|
||||
X86CPU.prototype.zeroSeg = function(seg)
|
||||
{
|
||||
if ((seg.sel & X86.SEL.MASK) && seg.dpl < this.nCPL && (seg.acc & X86.DESC.ACC.TYPE.CODE_CONFORMING) != X86.DESC.ACC.TYPE.CODE_CONFORMING) {
|
||||
seg.load(0);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* setAddrSize(size)
|
||||
*
|
||||
|
|
@ -1733,6 +1719,28 @@ X86CPU.prototype.checkMemoryException = function(addr, nb, fWrite)
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* getProtMode()
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @return {boolean} true if protected-mode, false if not
|
||||
*/
|
||||
X86CPU.prototype.getProtMode = function()
|
||||
{
|
||||
return !!(this.regCR0 & X86.CR0.MSW.PE);
|
||||
};
|
||||
|
||||
/**
|
||||
* getV68Mode()
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @return {boolean} true if V86-mode, false if not
|
||||
*/
|
||||
X86CPU.prototype.getV86Mode = function()
|
||||
{
|
||||
return !!(this.regPS & X86.PS.VM);
|
||||
};
|
||||
|
||||
/**
|
||||
* setProtMode(fProt, fV86)
|
||||
*
|
||||
|
|
@ -1752,12 +1760,12 @@ X86CPU.prototype.checkMemoryException = function(addr, nb, fWrite)
|
|||
X86CPU.prototype.setProtMode = function(fProt, fV86)
|
||||
{
|
||||
if (fProt === undefined) {
|
||||
fProt = !!(this.regCR0 & X86.CR0.MSW.PE);
|
||||
fProt = this.getProtMode();
|
||||
}
|
||||
if (fV86 === undefined) {
|
||||
fV86 = !!(this.regPS & X86.PS.VM);
|
||||
fV86 = this.getV86Mode();
|
||||
}
|
||||
if (DEBUG && (!fProt != !(this.regCR0 & X86.CR0.MSW.PE) || fV86 != !!(this.regPS & X86.PS.VM)) && this.messageEnabled()) {
|
||||
if (DEBUG && (fProt != this.getProtMode() || fV86 != this.getV86Mode()) && this.messageEnabled()) {
|
||||
this.printMessage("CPU switching to " + (fProt? (fV86? "v86" : "protected") : "real") + "-mode", this.bitsMessage, true);
|
||||
}
|
||||
this.aOpGrp6 = (fProt && !fV86? X86.aOpGrp6Prot : X86.aOpGrp6Real);
|
||||
|
|
|
|||
|
|
@ -462,9 +462,9 @@ X86.helpSRCxx = function()
|
|||
X86.helpCALLF = function(off, sel)
|
||||
{
|
||||
/*
|
||||
* Since we always push the return address AFTER calling setCSIP(), and since either push could trigger a
|
||||
* fault (eg, segment fault, page fault, etc), we must not only snapshot regLSP into opLSP, but also the
|
||||
* current CS into opCS, so that helpFault() can always make CALLF restartable. Ditto for opSS and the SS register.
|
||||
* Since we always push the return address AFTER calling setCSIP(), and since either push could trigger
|
||||
* a fault (eg, segment fault, page fault, etc), we must not only snapshot regSS and regLSP, but also regCS,
|
||||
* so that helpFault() can always make CALLF restartable.
|
||||
*/
|
||||
this.opCS = this.getCS();
|
||||
this.opSS = this.getSS();
|
||||
|
|
@ -532,11 +532,7 @@ X86.helpINT = function(nIDT, nError, nCycles)
|
|||
*/
|
||||
X86.helpIRET = function()
|
||||
{
|
||||
/*
|
||||
* Originally, we would snapshot regLSP into opLSP because newCS could trigger a segment fault,
|
||||
* but additionally, the stack segment could trigger either a segment fault or a page fault; indeed,
|
||||
* any operation that performs multiple stack modifications must take this precaution and snapshot regLSP.
|
||||
*/
|
||||
this.opSS = this.getSS();
|
||||
this.opLSP = this.regLSP;
|
||||
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesIRet;
|
||||
|
|
@ -612,6 +608,7 @@ X86.helpIRET = function()
|
|||
}
|
||||
|
||||
this.opLSP = X86.ADDR_INVALID;
|
||||
this.opSS = -1;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -626,11 +623,7 @@ X86.helpIRET = function()
|
|||
*/
|
||||
X86.helpRETF = function(n)
|
||||
{
|
||||
/*
|
||||
* Originally, we would snapshot regLSP into opLSP because newCS could trigger a segment fault,
|
||||
* but additionally, the stack segment could trigger either a segment fault or a page fault; indeed,
|
||||
* any operation that performs multiple stack modifications must take this precaution and snapshot regLSP.
|
||||
*/
|
||||
this.opSS = this.getSS();
|
||||
this.opLSP = this.regLSP;
|
||||
|
||||
var newIP = this.popWord();
|
||||
|
|
@ -656,16 +649,17 @@ X86.helpRETF = function(n)
|
|||
* it safe and using CODE_CONFORMING instead of CODE_CONFORMING_READABLE. Also, for the record, I've not
|
||||
* seen this situation occur yet (eg, in OS/2 1.0).
|
||||
*/
|
||||
this.zeroSeg(this.segDS);
|
||||
this.zeroSeg(this.segES);
|
||||
X86.zeroSeg.call(this, this.segDS);
|
||||
X86.zeroSeg.call(this, this.segES);
|
||||
if (I386 && this.model >= X86.MODEL_80386) {
|
||||
this.zeroSeg(this.segFS);
|
||||
this.zeroSeg(this.segGS);
|
||||
X86.zeroSeg.call(this, this.segFS);
|
||||
X86.zeroSeg.call(this, this.segGS);
|
||||
}
|
||||
}
|
||||
if (n == 2 && this.cIntReturn) this.checkIntReturn(this.regLIP);
|
||||
|
||||
this.opLSP = X86.ADDR_INVALID;
|
||||
this.opSS = -1;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -755,8 +749,8 @@ X86.helpFault = function(nFault, nError, nCycles, fHalt)
|
|||
*
|
||||
* TODO: The following opCS/opLIP/opSS/opLSP checks are primarily required for 80386-based machines
|
||||
* with paging enabled, because page faults introduce a new set of complex faults that our current
|
||||
* segment load "probes" are insufficient to catch. So as a stop-gap measure, we rely on these FOUR
|
||||
* "snapshot" registers to temporarily resolve the general instruction restartability problem.
|
||||
* segment load "probes" are insufficient to catch. So as a stop-gap measure, we rely on these four
|
||||
* "snapshot" registers to resolve the general instruction restartability problem (for now).
|
||||
*
|
||||
* If you want to closely examine the underlying causes of these more complex faults, set breakpoints
|
||||
* where indicated below, and examine the stack trace.
|
||||
|
|
@ -938,12 +932,13 @@ X86.helpCheckFault = function(nFault, nError, fHalt)
|
|||
* interrupts in V86-mode regardless (they generate a GP_FAULT if IOPL < 3, and even when IOPL == 3, only
|
||||
* the protected-mode IDT handler gets to run).
|
||||
*/
|
||||
if ((this.regPS & X86.PS.VM)) {
|
||||
if (this.regPS & X86.PS.VM) {
|
||||
if (nFault == X86.EXCEPTION.UD_FAULT && bOpcode == X86.OPCODE.ARPL ||
|
||||
nFault == X86.EXCEPTION.GP_FAULT && bOpcode == X86.OPCODE.INTN) {
|
||||
fHalt = false;
|
||||
}
|
||||
}
|
||||
// else if (DEBUG && nFault == X86.EXCEPTION.GP_FAULT && fHalt === undefined) fHalt = true;
|
||||
|
||||
/*
|
||||
* If fHalt has been explicitly set to false, we also take that as a cue to disable fault messages
|
||||
|
|
@ -1006,3 +1001,23 @@ X86.helpCheckFault = function(nFault, nError, fHalt)
|
|||
}
|
||||
return fHalt;
|
||||
};
|
||||
|
||||
/**
|
||||
* zeroSeg(seg)
|
||||
*
|
||||
* Helper to zero a segment register whenever transitioning to a less privileged (numerically higher) level.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {X86Seg} seg
|
||||
*/
|
||||
X86.zeroSeg = function(seg)
|
||||
{
|
||||
var acc = seg.acc & X86.DESC.ACC.TYPE.CODE_OR_DATA;
|
||||
if (seg.sel & X86.SEL.MASK) {
|
||||
if (acc == X86.DESC.ACC.TYPE.CODE_EXECONLY || // non-readable code segment (not allowed)
|
||||
acc == X86.DESC.ACC.TYPE.CODE_CONFORMING || // non-readable code segment (not allowed)
|
||||
acc < X86.DESC.ACC.TYPE.CODE_CONFORMING && seg.dpl < this.nCPL && seg.dpl < (seg.sel & X86.SEL.RPL)) {
|
||||
seg.load(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -805,6 +805,12 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fProbe)
|
|||
*/
|
||||
if (rpl >= this.cpl) {
|
||||
if (rpl > this.cpl) {
|
||||
/*
|
||||
* TODO: See if we can defer calling setSS() and setSP() until AFTER the final checks
|
||||
* below, because if, for example, the new CS is not PRESENT, we must generate a fault,
|
||||
* which in turn must restore the original stack, which means helpRETF() must snapshot
|
||||
* the stack registers.
|
||||
*/
|
||||
regSP = cpu.popWord();
|
||||
cpu.setSS(cpu.popWord(), true);
|
||||
cpu.setSP(regSP);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue