v1.19.5 update (fixes a CALLF bug and a VGA ATC bug, and adds improved WDEB386-style load notifications)
This commit is contained in:
parent
cb9e330cfa
commit
b00b524e01
8 changed files with 1349 additions and 1267 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1275,6 +1275,7 @@ if (DEBUGGER) {
|
||||||
|
|
||||||
if (Interrupts.WINDBG.ENABLED || Interrupts.WINDBGRM.ENABLED) {
|
if (Interrupts.WINDBG.ENABLED || Interrupts.WINDBGRM.ENABLED) {
|
||||||
this.fWinDbg = null;
|
this.fWinDbg = null;
|
||||||
|
this.cpu.addIntNotify(Interrupts.WINCB.VECTOR, this.intWindowsCallBack.bind(this));
|
||||||
this.cpu.addIntNotify(Interrupts.WINDBG.VECTOR, this.intWindowsDebugger.bind(this));
|
this.cpu.addIntNotify(Interrupts.WINDBG.VECTOR, this.intWindowsDebugger.bind(this));
|
||||||
}
|
}
|
||||||
if (Interrupts.WINDBGRM.ENABLED) {
|
if (Interrupts.WINDBGRM.ENABLED) {
|
||||||
|
|
@ -1336,13 +1337,13 @@ if (DEBUGGER) {
|
||||||
var len = this.getLong(dbgAddr, 4);
|
var len = this.getLong(dbgAddr, 4);
|
||||||
var dbgAddrDevice = this.newAddr(this.getLong(dbgAddr, 4), this.getShort(dbgAddr, 2));
|
var dbgAddrDevice = this.newAddr(this.getLong(dbgAddr, 4), this.getShort(dbgAddr, 2));
|
||||||
var dbgAddrModule = this.newAddr(this.getLong(dbgAddr, 4), this.getShort(dbgAddr, 2));
|
var dbgAddrModule = this.newAddr(this.getLong(dbgAddr, 4), this.getShort(dbgAddr, 2));
|
||||||
sel = this.getShort(dbgAddr, 2) || sel;
|
// sel = this.getShort(dbgAddr, 2) || sel;
|
||||||
var sModule = this.getSZ(dbgAddrModule).toUpperCase();
|
var sModule = this.getSZ(dbgAddrModule).toUpperCase();
|
||||||
var sDevice = this.getSZ(dbgAddrDevice).toUpperCase();
|
var sDevice = this.getSZ(dbgAddrDevice).toUpperCase();
|
||||||
var sSection = (fCode? "_CODE" : "_DATA") + str.toHex(nSeg, 2);
|
var sSection = (fCode? "_CODE" : "_DATA") + str.toHex(nSeg, 2);
|
||||||
if (fPrint) {
|
if (fPrint) {
|
||||||
/*
|
/*
|
||||||
* Mimic WDEB386 output
|
* Mimics WDEB386 output, except that WDEB386 only displays a linear address, omitting the selector.
|
||||||
*/
|
*/
|
||||||
this.println(sModule + '!' + sDevice + "!undefined " + (fCode? "code" : "data") + '(' + str.toHex(nSeg, 4) + ")=" + str.toHex(sel, 4) + ':' + str.toHex(off) + " len " + str.toHex(len));
|
this.println(sModule + '!' + sDevice + "!undefined " + (fCode? "code" : "data") + '(' + str.toHex(nSeg, 4) + ")=" + str.toHex(sel, 4) + ':' + str.toHex(off) + " len " + str.toHex(len));
|
||||||
}
|
}
|
||||||
|
|
@ -1351,6 +1352,55 @@ if (DEBUGGER) {
|
||||||
this.addSymbols(sel, off, len, aSymbols);
|
this.addSymbols(sel, off, len, aSymbols);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* intWindowsCallBack()
|
||||||
|
*
|
||||||
|
* This intercepts calls to Windows callback addresses, which use INT 0x30 (aka Transfer Space Fault).
|
||||||
|
*
|
||||||
|
* We're only interested in one particular callback: the one specifying VW32_Int41Dispatch (0x002A002A)
|
||||||
|
* in EAX.
|
||||||
|
*
|
||||||
|
* At the time that INT 0x30 occurs, a far 32-bit call has been made, preceded by a near 32-bit call,
|
||||||
|
* preceded by a 32-bit push of the Windows Debugger function # that would normally be in EAX if this had
|
||||||
|
* been an actual INT 0x41.
|
||||||
|
*
|
||||||
|
* NOTE: Regardless whether we're "handling" INT 0x41 or merely "monitoring" INT 0x41, as far as THIS
|
||||||
|
* interrupt is concerned, we always let the system process it, because execution never continues at the
|
||||||
|
* instruction following an INT 0x30; in fact, execution doesn't even continue after the far 32-bit call
|
||||||
|
* (even though the kernel places a "RET 4" after that call). So, rather than recreate all that automatic
|
||||||
|
* address popping, we let the system do it for us, since it's designed to work whether a debugger (eg,
|
||||||
|
* WDEB386's Debug VXD) is installed or not.
|
||||||
|
*
|
||||||
|
* @this {Debugger}
|
||||||
|
* @param {number} addr
|
||||||
|
* @return {boolean} true to proceed with the INT 0x30 software interrupt
|
||||||
|
*/
|
||||||
|
Debugger.prototype.intWindowsCallBack = function(addr)
|
||||||
|
{
|
||||||
|
var cpu = this.cpu;
|
||||||
|
|
||||||
|
if (this.fWinDbg != null && cpu.regEAX == 0x002A002A) {
|
||||||
|
|
||||||
|
var DX = cpu.regEDX & 0xffff;
|
||||||
|
var SI = cpu.regESI & 0xffff;
|
||||||
|
var dbgAddr = this.newAddr(cpu.getSP() + 0x0C, cpu.getSS());
|
||||||
|
var EAX = this.getLong(dbgAddr);
|
||||||
|
|
||||||
|
switch(EAX) {
|
||||||
|
case Interrupts.WINDBG.LOAD_SEG32:
|
||||||
|
/*
|
||||||
|
* SI == segment type:
|
||||||
|
* 0x0 code selector
|
||||||
|
* 0x1 data selector
|
||||||
|
* DX:EBX -> D386_Device_Params structure (see addSectionInfo() for details)
|
||||||
|
*/
|
||||||
|
this.addSectionInfo(this.newAddr(cpu.regEBX, DX), !SI, this.fWinDbg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* intWindowsDebugger()
|
* intWindowsDebugger()
|
||||||
*
|
*
|
||||||
|
|
@ -1430,7 +1480,7 @@ if (DEBUGGER) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (this.fWinDbg) {
|
if (MAXDEBUG && this.fWinDbg) {
|
||||||
this.println("INT 0x41: " + str.toHexWord(AX));
|
this.println("INT 0x41: " + str.toHexWord(AX));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -1561,7 +1611,7 @@ if (DEBUGGER) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (this.fWinDbgRM) {
|
if (MAXDEBUG && this.fWinDbgRM) {
|
||||||
this.println("INT 0x68: " + str.toHexByte(AH));
|
this.println("INT 0x68: " + str.toHexByte(AH));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -1616,7 +1666,7 @@ if (DEBUGGER) {
|
||||||
{
|
{
|
||||||
var cpu = this.cpu;
|
var cpu = this.cpu;
|
||||||
var AL = cpu.regEAX & 0xff;
|
var AL = cpu.regEAX & 0xff;
|
||||||
this.println("INT 0x68 callback: " + str.toHexByte(AL));
|
if (MAXDEBUG) this.println("INT 0x68 callback: " + str.toHexByte(AL));
|
||||||
if (AL == 5) {
|
if (AL == 5) {
|
||||||
cpu.regECX = cpu.regESI = 0; // our in-machine debugger footprint is zero
|
cpu.regECX = cpu.regESI = 0; // our in-machine debugger footprint is zero
|
||||||
cpu.regEAX = (cpu.regEAX & ~0xff) | 0x01;
|
cpu.regEAX = (cpu.regEAX & ~0xff) | 0x01;
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,10 @@ var Interrupts = {
|
||||||
MOUSE: 0x33,
|
MOUSE: 0x33,
|
||||||
ALT_DISK: 0x40, // HDC BIOS saves original FDC BIOS vector here
|
ALT_DISK: 0x40, // HDC BIOS saves original FDC BIOS vector here
|
||||||
ALT_VIDEO: 0x6D, // IBM VGA BIOS saves original video BIOS vector here
|
ALT_VIDEO: 0x6D, // IBM VGA BIOS saves original video BIOS vector here
|
||||||
WINDBG: { // Windows Debugger protected-mode interface
|
WINCB: {
|
||||||
|
VECTOR: 0x30 // Windows PM call-back interface (aka Transfer Space Fault)
|
||||||
|
},
|
||||||
|
WINDBG: { // Windows Debugger protected-mode interface
|
||||||
VECTOR: 0x41, // (AX==command)
|
VECTOR: 0x41, // (AX==command)
|
||||||
IS_LOADED: 0x004F, // DS_DebLoaded
|
IS_LOADED: 0x004F, // DS_DebLoaded
|
||||||
LOADED: 0xF386, // DS_DebPresent (returned in AX if Windows Debugger loaded)
|
LOADED: 0xF386, // DS_DebPresent (returned in AX if Windows Debugger loaded)
|
||||||
|
|
@ -69,7 +72,7 @@ var Interrupts = {
|
||||||
LOAD_SEG32: 0x0150, // DS_LoadSeg_32 (SI==0 if code, 1 if data; DX:EBX->D386_Device_Params)
|
LOAD_SEG32: 0x0150, // DS_LoadSeg_32 (SI==0 if code, 1 if data; DX:EBX->D386_Device_Params)
|
||||||
ENABLED: true // support for WINDBG interrupts can be disabled (but NOT if WINDBGRM is enabled)
|
ENABLED: true // support for WINDBG interrupts can be disabled (but NOT if WINDBGRM is enabled)
|
||||||
},
|
},
|
||||||
WINDBGRM: { // Windows Debugger real-mode interface
|
WINDBGRM: { // Windows Debugger real-mode interface
|
||||||
VECTOR: 0x68, // (AH==command)
|
VECTOR: 0x68, // (AH==command)
|
||||||
IS_LOADED: 0x43, // D386_Identify
|
IS_LOADED: 0x43, // D386_Identify
|
||||||
LOADED: 0xF386, // D386_Id (returned in AX if Windows Debugger loaded)
|
LOADED: 0xF386, // D386_Id (returned in AX if Windows Debugger loaded)
|
||||||
|
|
@ -77,7 +80,7 @@ var Interrupts = {
|
||||||
LOAD_SEG: 0x50, // D386_Load_Segment (AL=segment type, ES:DI->D386_Device_Params)
|
LOAD_SEG: 0x50, // D386_Load_Segment (AL=segment type, ES:DI->D386_Device_Params)
|
||||||
ENABLED: true // support for WINDBGRM interrupts can be disabled
|
ENABLED: true // support for WINDBGRM interrupts can be disabled
|
||||||
},
|
},
|
||||||
FUNCS: {} // filled in only if DEBUGGER is true
|
FUNCS: {} // filled in only if DEBUGGER is true
|
||||||
};
|
};
|
||||||
|
|
||||||
if (DEBUGGER) {
|
if (DEBUGGER) {
|
||||||
|
|
|
||||||
|
|
@ -2461,6 +2461,7 @@ Card.prototype.dumpVideoCard = function()
|
||||||
this.dumpRegs(" GRC", this.regGRCIndx, this.regGRCData, this.asGRCRegs);
|
this.dumpRegs(" GRC", this.regGRCIndx, this.regGRCData, this.asGRCRegs);
|
||||||
this.dumpRegs(" SEQ", this.regSEQIndx, this.regSEQData, this.asSEQRegs);
|
this.dumpRegs(" SEQ", this.regSEQIndx, this.regSEQData, this.asSEQRegs);
|
||||||
this.dumpRegs(" ATC", this.regATCIndx, this.regATCData, this.asATCRegs);
|
this.dumpRegs(" ATC", this.regATCIndx, this.regATCData, this.asATCRegs);
|
||||||
|
this.dumpRegs(" ATCINDX", this.regATCIndx);
|
||||||
this.dbg.println(" ATCDATA: " + this.fATCData);
|
this.dbg.println(" ATCDATA: " + this.fATCData);
|
||||||
this.dumpRegs(" FEAT", this.regFeat);
|
this.dumpRegs(" FEAT", this.regFeat);
|
||||||
this.dumpRegs(" MISC", this.regMisc);
|
this.dumpRegs(" MISC", this.regMisc);
|
||||||
|
|
@ -5894,20 +5895,44 @@ Video.prototype.outFeat = function(port, bOut, addrFrom)
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* inATC(port, addrFrom)
|
* inATCIndx(port, addrFrom)
|
||||||
|
*
|
||||||
|
* Technically, port 0x3C0 is readable only on a VGA, but we allow reads on an EGA as well,
|
||||||
|
* primarily for debugging purposes. Moreover, ATC port reads do NOT toggle the ATC address/data
|
||||||
|
* flip-flop; only writes have that effect.
|
||||||
*
|
*
|
||||||
* @this {Video}
|
* @this {Video}
|
||||||
* @param {number} port (0x3C0)
|
* @param {number} port (0x3C0)
|
||||||
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
|
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
|
||||||
* @return {number}
|
* @return {number}
|
||||||
*/
|
*/
|
||||||
Video.prototype.inATC = function(port, addrFrom)
|
Video.prototype.inATCIndx = function(port, addrFrom)
|
||||||
{
|
{
|
||||||
var b = this.cardEGA.fATCData? this.cardEGA.regATCData[this.cardEGA.regATCIndx & Card.ATC.INDX_MASK] : this.cardEGA.regATCIndx;
|
var b = this.cardEGA.regATCIndx;
|
||||||
if (!addrFrom || this.messageEnabled()) {
|
if (!addrFrom || this.messageEnabled()) {
|
||||||
this.printMessageIO(Card.ATC.PORT, null, addrFrom, "ATC." + (this.cardEGA.fATCData? this.cardEGA.asATCRegs[this.cardEGA.regATCIndx & Card.ATC.INDX_MASK] : "INDX"), b);
|
this.printMessageIO(Card.ATC.PORT, null, addrFrom, "ATC.INDX", b);
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* inATCData(port, addrFrom)
|
||||||
|
*
|
||||||
|
* Technically, port 0x3C0 is readable only on a VGA, but we allow reads on an EGA as well,
|
||||||
|
* primarily for debugging purposes. Moreover, ATC port reads do NOT toggle the ATC address/data
|
||||||
|
* flip-flop; only writes have that effect.
|
||||||
|
*
|
||||||
|
* @this {Video}
|
||||||
|
* @param {number} port (0x3C1)
|
||||||
|
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
Video.prototype.inATCData = function(port, addrFrom)
|
||||||
|
{
|
||||||
|
var b = this.cardEGA.regATCData[this.cardEGA.regATCIndx & Card.ATC.INDX_MASK];
|
||||||
|
if (!addrFrom || this.messageEnabled()) {
|
||||||
|
this.printMessageIO(Card.ATC.PORT, null, addrFrom, "ATC." + this.cardEGA.asATCRegs[this.cardEGA.regATCIndx & Card.ATC.INDX_MASK], b);
|
||||||
}
|
}
|
||||||
this.cardEGA.fATCData = !this.cardEGA.fATCData;
|
|
||||||
return b;
|
return b;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -6880,8 +6905,8 @@ Video.aCGAPortOutput = {
|
||||||
};
|
};
|
||||||
|
|
||||||
Video.aEGAPortInput = {
|
Video.aEGAPortInput = {
|
||||||
0x3C0: Video.prototype.inATC, // technically, only readable on a VGA, but I want the Debugger to be able to read this, too
|
0x3C0: Video.prototype.inATCIndx, // technically, only readable on a VGA, but I want the Debugger to be able to read this, too
|
||||||
0x3C1: Video.prototype.inATC, // technically, only readable on a VGA, but I want the Debugger to be able to read this, too
|
0x3C1: Video.prototype.inATCData, // technically, only readable on a VGA, but I want the Debugger to be able to read this, too
|
||||||
0x3C2: Video.prototype.inStatus0,
|
0x3C2: Video.prototype.inStatus0,
|
||||||
0x3C4: Video.prototype.inSEQIndx, // technically, only readable on a VGA, but I want the Debugger to be able to read this, too
|
0x3C4: Video.prototype.inSEQIndx, // technically, only readable on a VGA, but I want the Debugger to be able to read this, too
|
||||||
0x3C5: Video.prototype.inSEQData, // technically, only readable on a VGA, but I want the Debugger to be able to read this, too
|
0x3C5: Video.prototype.inSEQData, // technically, only readable on a VGA, but I want the Debugger to be able to read this, too
|
||||||
|
|
@ -6892,7 +6917,7 @@ Video.aEGAPortInput = {
|
||||||
/*
|
/*
|
||||||
* WARNING: Unlike the EGA, a standard VGA does not support writes to 0x3C1, but it's easier for me to leave that
|
* WARNING: Unlike the EGA, a standard VGA does not support writes to 0x3C1, but it's easier for me to leave that
|
||||||
* ability in place, treating the VGA as a superset of the EGA as much as possible; will any code break because word
|
* ability in place, treating the VGA as a superset of the EGA as much as possible; will any code break because word
|
||||||
* I/O to port 0x3C0 actually works? Possibly, but highly unlikely.
|
* OUTs to port 0x3C0 (and/or byte OUTs to port 0x3C1) actually work? Possibly, but highly unlikely.
|
||||||
*/
|
*/
|
||||||
Video.aEGAPortOutput = {
|
Video.aEGAPortOutput = {
|
||||||
0x3BA: Video.prototype.outFeat,
|
0x3BA: Video.prototype.outFeat,
|
||||||
|
|
|
||||||
|
|
@ -562,7 +562,7 @@ X86.fnCALLF = function CALLF(off, sel)
|
||||||
{
|
{
|
||||||
var oldCS = this.getCS();
|
var oldCS = this.getCS();
|
||||||
var oldIP = this.getIP();
|
var oldIP = this.getIP();
|
||||||
var oldSize = this.segCS.sizeData;
|
var oldSize = (I386? this.sizeData : 2);
|
||||||
if (this.setCSIP(off, sel, true) != null) {
|
if (this.setCSIP(off, sel, true) != null) {
|
||||||
this.pushData(oldCS, oldSize);
|
this.pushData(oldCS, oldSize);
|
||||||
this.pushData(oldIP, oldSize);
|
this.pushData(oldIP, oldSize);
|
||||||
|
|
@ -1415,6 +1415,10 @@ X86.fnINT = function INT(nIDT, nError, nCycles)
|
||||||
var oldIP = this.getIP();
|
var oldIP = this.getIP();
|
||||||
var addr = this.segCS.loadIDT(nIDT);
|
var addr = this.segCS.loadIDT(nIDT);
|
||||||
if (addr !== X86.ADDR_INVALID) {
|
if (addr !== X86.ADDR_INVALID) {
|
||||||
|
/*
|
||||||
|
* TODO: Harmonize this with the code in fnCALLF(), which relies on the OPERAND size in
|
||||||
|
* effect at the time of the call, NOT the size of the new segCS.
|
||||||
|
*/
|
||||||
var size = this.segCS.sizeFrame;
|
var size = this.segCS.sizeFrame;
|
||||||
this.pushData(oldPS, size);
|
this.pushData(oldPS, size);
|
||||||
this.pushData(oldCS, size);
|
this.pushData(oldCS, size);
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue