A few Debugger fixes whilst tracking down TSS issues

This commit is contained in:
Jeff Parsons 2015-05-16 09:58:51 -07:00 committed by jeffpar
commit 30d0d22e41
3 changed files with 235 additions and 198 deletions

View file

@ -1424,7 +1424,7 @@ if (DEBUGGER) {
* should be done only as a last resort.
*
* @param {number|null|undefined} sel
* @return {X86Seg} seg
* @return {X86Seg|null} seg
*/
Debugger.prototype.getSegment = function(sel)
{
@ -1436,6 +1436,7 @@ if (DEBUGGER) {
if (sel === this.cpu.getFS()) return this.cpu.segFS;
if (sel === this.cpu.getGS()) return this.cpu.segGS;
}
if (this.nBreakSuppress) return null;
var seg = new X86Seg(this.cpu, X86Seg.ID.DEBUG, "DBG");
/*
* Note the load() function's fSuppress parameter, which the Debugger should ALWAYS set to true
@ -1466,13 +1467,16 @@ if (DEBUGGER) {
*/
var addr = dbgAddr.addr;
if (addr == null) {
addr = X86.ADDR_INVALID;
var seg = this.getSegment(dbgAddr.sel);
if (!fWrite) {
addr = seg.checkRead(dbgAddr.off, cb || 1, true);
} else {
addr = seg.checkWrite(dbgAddr.off, cb || 1, true);
if (seg) {
if (!fWrite) {
addr = seg.checkRead(dbgAddr.off, cb || 1, true);
} else {
addr = seg.checkWrite(dbgAddr.off, cb || 1, true);
}
dbgAddr.addr = addr;
}
dbgAddr.addr = addr;
}
return addr;
};
@ -1639,8 +1643,8 @@ if (DEBUGGER) {
Debugger.prototype.checkLimit = function(dbgAddr)
{
if (dbgAddr.sel != null) {
var limit = this.getSegment(dbgAddr.sel).limit;
if (dbgAddr.off > limit) {
var seg = this.getSegment(dbgAddr.sel);
if (!seg || dbgAddr.off > seg.limit) {
dbgAddr.off = 0;
dbgAddr.addr = null;
}
@ -1816,8 +1820,8 @@ if (DEBUGGER) {
}
var seg = this.getSegment(sel);
this.println("dumpDesc(" + str.toHexWord(seg.sel) + "): %" + str.toHex(seg.addrDesc, this.cchAddr));
this.println("dumpDesc(" + str.toHexWord(seg? seg.sel : sel) + "): %" + str.toHex(seg? seg.addrDesc : null, this.cchAddr));
if (!seg) return;
var sType;
var fGate = false;
@ -1879,7 +1883,68 @@ if (DEBUGGER) {
* been incorporated into the limit and base properties of the segment register; all we care about here
* are whether EXT contains any of the AVAIL (0x10), BIG (0x40) or LIMITPAGES (0x80) bits.
*/
this.println(sDump + " dpl=" + str.toHexByte(seg.dpl) + " type=" + str.toHexByte(seg.type >> 8) + " (" + sType + ")" + " ext=" + str.toHexWord(seg.ext & ~(X86.DESC.EXT.LIMIT1619 | X86.DESC.EXT.BASE2431)));
this.println(sDump + " type=" + str.toHexByte(seg.type >> 8) + " (" + sType + ")" + " ext=" + str.toHexWord(seg.ext & ~(X86.DESC.EXT.LIMIT1619 | X86.DESC.EXT.BASE2431)) + " dpl=" + str.toHexByte(seg.dpl));
};
/**
* dumpHistory(sCount)
*
* @this {Debugger}
* @param {string|undefined} sCount is the number of instructions to rewind to (default is 10)
*/
Debugger.prototype.dumpHistory = function(sCount)
{
var sMore = "";
var cLines = 10;
var iHistory = this.iOpcodeHistory;
var aHistory = this.aOpcodeHistory;
if (aHistory.length) {
var n = (sCount === undefined? this.nextHistory : +sCount);
if (isNaN(n))
n = cLines;
else
sMore = "more ";
if (n > aHistory.length) {
this.println("note: only " + aHistory.length + " available");
n = aHistory.length;
}
iHistory -= n;
if (iHistory < 0) {
if (aHistory[aHistory.length - 1][1] != null) {
iHistory += aHistory.length;
} else {
n = iHistory + n;
iHistory = 0;
}
}
if (sCount !== undefined) {
this.println(n + " instructions earlier:");
}
while (cLines && iHistory != this.iOpcodeHistory) {
var dbgAddr = aHistory[iHistory++];
if (dbgAddr.sel == null) break;
/*
* We must create a new dbgAddr from the address we obtained from aHistory, because dbgAddr
* was a reference, not a copy, and we don't want getInstruction() modifying the original.
*/
dbgAddr = this.newAddr(dbgAddr.off, dbgAddr.sel, dbgAddr.addr);
this.println(this.getInstruction(dbgAddr, "history", n--));
/*
* If there was an OPERAND or ADDRESS override on the previous instruction, getInstruction()
* will have automatically disassembled the next instruction, so skip one more history entry.
*/
if (dbgAddr.fOverride) {
iHistory++; n--;
}
if (iHistory >= aHistory.length) iHistory = 0;
this.nextHistory = n;
cLines--;
}
}
if (cLines == 10) {
this.println("no " + sMore + "history available");
this.nextHistory = undefined;
}
};
/**
@ -1904,7 +1969,8 @@ if (DEBUGGER) {
seg = this.getSegment(sel);
}
this.println("dumpTSS(" + str.toHexWord(seg.sel) + "): %" + str.toHex(seg.base, this.cchAddr));
this.println("dumpTSS(" + str.toHexWord(seg? seg.sel : sel) + "): %" + str.toHex(seg? seg.base : null, this.cchAddr));
if (!seg) return;
var sDump = "";
for (var sField in Debugger.aTSSFields) {
@ -2829,6 +2895,12 @@ if (DEBUGGER) {
}
}
this.aBreakWrite = ["write"];
/*
* nBreakSuppress ensures we can't get into an infinite loop where a breakpoint lookup requires
* reading a segment descriptor via getSegment(), and that triggers more memory reads, which triggers
* more breakpoint checks.
*/
this.nBreakSuppress = 0;
};
/**
@ -3017,39 +3089,42 @@ if (DEBUGGER) {
* or history data (see checkInstruction), since we might not actually execute the current instruction.
*/
var fBreak = false;
addr = this.mapBreakpoint(addr);
for (var i = 1; i < aBreak.length; i++) {
if (!this.nBreakSuppress++) {
addr = this.mapBreakpoint(addr);
for (var i = 1; i < aBreak.length; i++) {
var dbgAddrBreak = aBreak[i];
var dbgAddrBreak = aBreak[i];
/*
* We need to zap the linear address field of the breakpoint address before
* calling getAddr(), to force it to recalculate the linear address every time,
* unless this is a breakpoint on a linear address (as indicated by a -1 offset).
*/
if (dbgAddrBreak.off != -1) dbgAddrBreak.addr = null;
/*
* We need to zap the linear address field of the breakpoint address before
* calling getAddr(), to force it to recalculate the linear address every time,
* unless this is a breakpoint on a linear address (as indicated by a -1 offset).
*/
if (dbgAddrBreak.off != -1) dbgAddrBreak.addr = null;
/*
* We used to calculate the linear address of the breakpoint at the time the
* breakpoint was added, so that a breakpoint set in one mode (eg, in real-mode)
* would still work as intended if the mode changed later (eg, to protected-mode).
*
* However, that created difficulties setting protected-mode breakpoints in segments
* that might not be defined yet, or that could move in physical memory.
*
* If you want to create a real-mode breakpoint that will break regardless of mode,
* use the physical address of the real-mode memory location instead.
*/
if (addr == this.mapBreakpoint(this.getAddr(dbgAddrBreak))) {
if (dbgAddrBreak.fTempBreak) {
this.findBreakpoint(aBreak, dbgAddrBreak, true);
} else if (!fTemp) {
this.println("breakpoint hit: " + this.hexAddr(dbgAddrBreak) + " (" + aBreak[0] + ")");
/*
* We used to calculate the linear address of the breakpoint at the time the
* breakpoint was added, so that a breakpoint set in one mode (eg, in real-mode)
* would still work as intended if the mode changed later (eg, to protected-mode).
*
* However, that created difficulties setting protected-mode breakpoints in segments
* that might not be defined yet, or that could move in physical memory.
*
* If you want to create a real-mode breakpoint that will break regardless of mode,
* use the physical address of the real-mode memory location instead.
*/
if (addr == this.mapBreakpoint(this.getAddr(dbgAddrBreak))) {
if (dbgAddrBreak.fTempBreak) {
this.findBreakpoint(aBreak, dbgAddrBreak, true);
} else if (!fTemp) {
this.println("breakpoint hit: " + this.hexAddr(dbgAddrBreak) + " (" + aBreak[0] + ")");
}
fBreak = true;
break;
}
fBreak = true;
break;
}
}
this.nBreakSuppress--;
return fBreak;
};
@ -4167,9 +4242,10 @@ if (DEBUGGER) {
sDumpers += ",state,symbols";
this.println("\ndump commands:");
this.println("\tdb [a] [#] dump # bytes at address a");
if (BACKTRACK) this.println("\tdi [a] dump backtrack info at address a");
this.println("\tdw [a] [#] dump # words at address a");
this.println("\tdd [a] [#] dump # dwords at address a");
this.println("\tdh [#] dump # instructions prior");
if (BACKTRACK) this.println("\tdi [a] dump backtrack info at address a");
if (sDumpers.length) this.println("dump extensions:\n\t" + sDumpers);
return;
}
@ -4181,6 +4257,10 @@ if (DEBUGGER) {
this.dumpSymbols();
return;
}
if (sCmd == "dh") {
this.dumpHistory(sAddr);
return;
}
if (sCmd == "ds") { // transform a "ds" command into a "d desc" command
sCmd = 'd';
sLen = sAddr;
@ -4326,57 +4406,7 @@ if (DEBUGGER) {
this.stopCPU();
return;
}
var sMore = "";
var cLines = 10;
var iHistory = this.iOpcodeHistory;
var aHistory = this.aOpcodeHistory;
if (aHistory.length) {
var n = (sCount === undefined? this.nextHistory : +sCount);
if (isNaN(n))
n = cLines;
else
sMore = "more ";
if (n > aHistory.length) {
this.println("note: only " + aHistory.length + " available");
n = aHistory.length;
}
iHistory -= n;
if (iHistory < 0) {
if (aHistory[aHistory.length - 1][1] != null) {
iHistory += aHistory.length;
} else {
n = iHistory + n;
iHistory = 0;
}
}
if (sCount !== undefined) {
this.println(n + " instructions earlier:");
}
while (cLines && iHistory != this.iOpcodeHistory) {
var dbgAddr = aHistory[iHistory++];
if (dbgAddr.sel == null) break;
/*
* We must create a new dbgAddr from the address we obtained from aHistory, because dbgAddr
* was a reference, not a copy, and we don't want getInstruction() modifying the original.
*/
dbgAddr = this.newAddr(dbgAddr.off, dbgAddr.sel, dbgAddr.addr);
this.println(this.getInstruction(dbgAddr, "history", n--));
/*
* If there was an OPERAND or ADDRESS override on the previous instruction, getInstruction()
* will have automatically disassembled the next instruction, so skip one more history entry.
*/
if (dbgAddr.fOverride) {
iHistory++; n--;
}
if (iHistory >= aHistory.length) iHistory = 0;
this.nextHistory = n;
cLines--;
}
}
if (cLines == 10) {
this.println("no " + sMore + "history available");
this.nextHistory = undefined;
}
this.dumpHistory(sCount);
};
/**

View file

@ -3802,11 +3802,10 @@ X86.opHLT = function HLT()
this.intFlags |= X86.INTFLAG.HALT;
this.nStepCycles -= 2;
/*
* If a Debugger is present AND Debugger checks are enabled (eg, one or more breakpoints are set,
* or the global DEBUG flag is set, etc), then we REALLY halt the CPU, on the theory that whoever's
* using the Debugger would like to see HLTs.
* If a Debugger is present and the HALT message category is enabled, then we REALLY halt the CPU,
* on the theory that whoever's using the Debugger would like to see HLTs.
*/
if (DEBUGGER && this.dbg && this.dbg.checksEnabled(true)) {
if (DEBUGGER && this.dbg && this.messageEnabled(Messages.HALT)) {
this.advanceIP(-1); // this is purely for the Debugger's benefit, to show the HLT
this.stopCPU();
return;

View file

@ -44,7 +44,7 @@ if (typeof module !== 'undefined') {
* @property {number} sel
* @property {number} limit (in protected-mode, this comes from descriptor word 0x0)
* @property {number} base (in protected-mode, this comes from descriptor word 0x2)
* @property {number} acc (in protected-mode, this comes from descriptor word 0x4, masked with 0xff00; bits 0-7 supplement base bits 16-23)
* @property {number} acc (in protected-mode, this comes from descriptor word 0x4; bits 0-7 supplement base bits 16-23)
* @property {number} ext (in protected-mode, this is descriptor word 0x6, 80386 only; supplements limit bits 16-19 and base bits 24-31)
*
* TODO: Determine what good, if any, these class annotations are for either an IDE like WebStorm or a tool like
@ -409,102 +409,6 @@ X86Seg.prototype.checkWriteProtDisallowed = function checkWriteProtDisallowed(of
return X86.ADDR_INVALID;
};
/**
* switchTSS(selNew, fNest)
*
* Implements TSS (Task State Segment) task switching.
*
* NOTES: This typically occurs during double-fault processing, because the IDT entry for DF_FAULT normally
* contains a task gate. Interestingly, if we force a GP_FAULT to occur at a sufficiently early point in the
* OS/2 1.0 initialization code, OS/2 does a nice job of displaying the GP fault and then shutting down:
*
* 0090:067B FB STI
* 0090:067C EBFD JMP 067B
*
* but it may not have yet reprogrammed the master PIC to re-vector hardware interrupts to IDT entries 0x50-0x57,
* so when the next timer interrupt (IRQ 0) occurs, it vectors through IDT entry 0x08, which is the DF_FAULT
* vector. A spurious double-fault is generated, and a clean shutdown turns into a messy crash.
*
* Of course, that all could have been avoided if IBM had heeded Intel's advice and not used Intel-reserved IDT
* entries for PC interrupts.
*
* TODO: Add 80386 TSS support (including CR3 support).
*
* @this {X86Seg}
* @param {number} selNew
* @param {boolean} fNest is true if nesting, false if un-nesting
* @return {boolean} true if successful, false if error
*/
X86Seg.prototype.switchTSS = function switchTSS(selNew, fNest)
{
var cpu = this.cpu;
cpu.assert(this === cpu.segCS);
var addrOld = cpu.segTSS.base;
var cplOld = this.cpl;
var selOld = cpu.segTSS.sel;
if (!fNest) {
if (cpu.segTSS.type != X86.DESC.ACC.TYPE.TSS_BUSY) {
X86.fnFault.call(cpu, X86.EXCEPTION.TS_FAULT, selNew, true);
return false;
}
cpu.setShort(cpu.segTSS.addrDesc + X86.DESC.ACC.OFFSET, (cpu.segTSS.acc & ~X86.DESC.ACC.TYPE.TSS_BUSY) | X86.DESC.ACC.TYPE.TSS);
}
if (cpu.segTSS.load(selNew) === X86.ADDR_INVALID) {
return false;
}
var addrNew = cpu.segTSS.base;
if (DEBUG && DEBUGGER && this.dbg && this.dbg.messageEnabled(Messages.TSS)) {
this.dbg.message((fNest? "Task switch" : "Task return") + ": TR " + str.toHexWord(selOld) + " (%" + str.toHex(addrOld, 6) + "), new TR " + str.toHexWord(selNew) + " (%" + str.toHex(addrNew, 6) + ")");
}
if (fNest) {
if (cpu.segTSS.type == X86.DESC.ACC.TYPE.TSS_BUSY) {
X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, selNew, true);
return false;
}
cpu.setShort(cpu.segTSS.addrDesc + X86.DESC.ACC.OFFSET, cpu.segTSS.acc |= X86.DESC.ACC.TYPE.TSS_BUSY);
cpu.segTSS.type = X86.DESC.ACC.TYPE.TSS_BUSY;
}
cpu.setShort(addrOld + X86.TSS.TASK_IP, cpu.getIP());
cpu.setShort(addrOld + X86.TSS.TASK_PS, cpu.getPS());
cpu.setShort(addrOld + X86.TSS.TASK_AX, cpu.regEAX);
cpu.setShort(addrOld + X86.TSS.TASK_CX, cpu.regECX);
cpu.setShort(addrOld + X86.TSS.TASK_DX, cpu.regEDX);
cpu.setShort(addrOld + X86.TSS.TASK_BX, cpu.regEBX);
cpu.setShort(addrOld + X86.TSS.TASK_SP, cpu.getSP());
cpu.setShort(addrOld + X86.TSS.TASK_BP, cpu.regEBP);
cpu.setShort(addrOld + X86.TSS.TASK_SI, cpu.regESI);
cpu.setShort(addrOld + X86.TSS.TASK_DI, cpu.regEDI);
cpu.setShort(addrOld + X86.TSS.TASK_ES, cpu.segES.sel);
cpu.setShort(addrOld + X86.TSS.TASK_CS, cpu.segCS.sel);
cpu.setShort(addrOld + X86.TSS.TASK_SS, cpu.segSS.sel);
cpu.setShort(addrOld + X86.TSS.TASK_DS, cpu.segDS.sel);
var offSS = X86.TSS.TASK_SS;
var offSP = X86.TSS.TASK_SP;
cpu.setPS(cpu.getShort(addrNew + X86.TSS.TASK_PS) | (fNest? X86.PS.NT : 0));
cpu.assert(!fNest || !!(cpu.regPS & X86.PS.NT));
cpu.regEAX = cpu.getShort(addrNew + X86.TSS.TASK_AX);
cpu.regECX = cpu.getShort(addrNew + X86.TSS.TASK_CX);
cpu.regEDX = cpu.getShort(addrNew + X86.TSS.TASK_DX);
cpu.regEBX = cpu.getShort(addrNew + X86.TSS.TASK_BX);
cpu.regEBP = cpu.getShort(addrNew + X86.TSS.TASK_BP);
cpu.regESI = cpu.getShort(addrNew + X86.TSS.TASK_SI);
cpu.regEDI = cpu.getShort(addrNew + X86.TSS.TASK_DI);
cpu.segES.load(cpu.getShort(addrNew + X86.TSS.TASK_ES));
cpu.segDS.load(cpu.getShort(addrNew + X86.TSS.TASK_DS));
cpu.setCSIP(cpu.getShort(addrNew + X86.TSS.TASK_IP), cpu.getShort(addrNew + X86.TSS.TASK_CS));
if (this.cpl < cplOld) {
offSP = (this.cpl << 2) + X86.TSS.CPL0_SP;
offSS = offSP + 2;
}
cpu.setSS(cpu.getShort(addrNew + offSS), true);
cpu.setSP(cpu.getShort(addrNew + offSP));
cpu.segLDT.load(cpu.getShort(addrNew + X86.TSS.TASK_LDT));
if (fNest) cpu.setShort(addrNew + X86.TSS.PREV_TSS, selOld);
cpu.regCR0 |= X86.CR0.MSW.TS;
return true;
};
/**
* loadAcc(sel, fGDT)
*
@ -567,7 +471,7 @@ X86Seg.prototype.loadDesc6 = function(addrDesc, sel)
this.addrDesc = addrDesc;
this.updateMode(true);
this.messageSeg(sel, base, limit, acc);
this.messageSeg(sel, base, limit, this.type);
return base;
};
@ -650,6 +554,14 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
}
fGate = false;
}
else if (type == X86.DESC.ACC.TYPE.TSS) {
if (!this.switchTSS(sel, true)) {
base = addrDesc = X86.ADDR_INVALID;
break;
}
if (DEBUG) cpu.stopCPU();
return this.base;
}
else if (type == X86.DESC.ACC.TYPE.GATE_CALL) {
fGate = true;
regPSMask = ~0;
@ -807,10 +719,106 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
this.updateMode(true);
break;
}
if (!fSuppress) this.messageSeg(sel, base, limit, acc, ext);
if (!fSuppress) this.messageSeg(sel, base, limit, type, ext);
return base;
};
/**
* switchTSS(selNew, fNest)
*
* Implements TSS (Task State Segment) task switching.
*
* NOTES: This typically occurs during double-fault processing, because the IDT entry for DF_FAULT normally
* contains a task gate. Interestingly, if we force a GP_FAULT to occur at a sufficiently early point in the
* OS/2 1.0 initialization code, OS/2 does a nice job of displaying the GP fault and then shutting down:
*
* 0090:067B FB STI
* 0090:067C EBFD JMP 067B
*
* but it may not have yet reprogrammed the master PIC to re-vector hardware interrupts to IDT entries 0x50-0x57,
* so when the next timer interrupt (IRQ 0) occurs, it vectors through IDT entry 0x08, which is the DF_FAULT
* vector. A spurious double-fault is generated, and a clean shutdown turns into a messy crash.
*
* Of course, that all could have been avoided if IBM had heeded Intel's advice and not used Intel-reserved IDT
* entries for PC interrupts.
*
* TODO: Add 80386 TSS support (including CR3 support).
*
* @this {X86Seg}
* @param {number} selNew
* @param {boolean} fNest is true if nesting, false if un-nesting
* @return {boolean} true if successful, false if error
*/
X86Seg.prototype.switchTSS = function switchTSS(selNew, fNest)
{
var cpu = this.cpu;
cpu.assert(this === cpu.segCS);
var addrOld = cpu.segTSS.base;
var cplOld = this.cpl;
var selOld = cpu.segTSS.sel;
if (!fNest) {
if (cpu.segTSS.type != X86.DESC.ACC.TYPE.TSS_BUSY) {
X86.fnFault.call(cpu, X86.EXCEPTION.TS_FAULT, selNew, true);
return false;
}
cpu.setShort(cpu.segTSS.addrDesc + X86.DESC.ACC.OFFSET, (cpu.segTSS.acc & ~X86.DESC.ACC.TYPE.TSS_BUSY) | X86.DESC.ACC.TYPE.TSS);
}
if (cpu.segTSS.load(selNew) === X86.ADDR_INVALID) {
return false;
}
var addrNew = cpu.segTSS.base;
if (DEBUG && DEBUGGER && this.dbg && this.dbg.messageEnabled(Messages.TSS)) {
this.dbg.message((fNest? "Task switch" : "Task return") + ": TR " + str.toHexWord(selOld) + " (%" + str.toHex(addrOld, 6) + "), new TR " + str.toHexWord(selNew) + " (%" + str.toHex(addrNew, 6) + ")");
}
if (fNest) {
if (cpu.segTSS.type == X86.DESC.ACC.TYPE.TSS_BUSY) {
X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, selNew, true);
return false;
}
cpu.setShort(cpu.segTSS.addrDesc + X86.DESC.ACC.OFFSET, cpu.segTSS.acc |= X86.DESC.ACC.TYPE.TSS_BUSY);
cpu.segTSS.type = X86.DESC.ACC.TYPE.TSS_BUSY;
}
cpu.setShort(addrOld + X86.TSS.TASK_IP, cpu.getIP());
cpu.setShort(addrOld + X86.TSS.TASK_PS, cpu.getPS());
cpu.setShort(addrOld + X86.TSS.TASK_AX, cpu.regEAX);
cpu.setShort(addrOld + X86.TSS.TASK_CX, cpu.regECX);
cpu.setShort(addrOld + X86.TSS.TASK_DX, cpu.regEDX);
cpu.setShort(addrOld + X86.TSS.TASK_BX, cpu.regEBX);
cpu.setShort(addrOld + X86.TSS.TASK_SP, cpu.getSP());
cpu.setShort(addrOld + X86.TSS.TASK_BP, cpu.regEBP);
cpu.setShort(addrOld + X86.TSS.TASK_SI, cpu.regESI);
cpu.setShort(addrOld + X86.TSS.TASK_DI, cpu.regEDI);
cpu.setShort(addrOld + X86.TSS.TASK_ES, cpu.segES.sel);
cpu.setShort(addrOld + X86.TSS.TASK_CS, cpu.segCS.sel);
cpu.setShort(addrOld + X86.TSS.TASK_SS, cpu.segSS.sel);
cpu.setShort(addrOld + X86.TSS.TASK_DS, cpu.segDS.sel);
var offSS = X86.TSS.TASK_SS;
var offSP = X86.TSS.TASK_SP;
cpu.setPS(cpu.getShort(addrNew + X86.TSS.TASK_PS) | (fNest? X86.PS.NT : 0));
cpu.assert(!fNest || !!(cpu.regPS & X86.PS.NT));
cpu.regEAX = cpu.getShort(addrNew + X86.TSS.TASK_AX);
cpu.regECX = cpu.getShort(addrNew + X86.TSS.TASK_CX);
cpu.regEDX = cpu.getShort(addrNew + X86.TSS.TASK_DX);
cpu.regEBX = cpu.getShort(addrNew + X86.TSS.TASK_BX);
cpu.regEBP = cpu.getShort(addrNew + X86.TSS.TASK_BP);
cpu.regESI = cpu.getShort(addrNew + X86.TSS.TASK_SI);
cpu.regEDI = cpu.getShort(addrNew + X86.TSS.TASK_DI);
cpu.segES.load(cpu.getShort(addrNew + X86.TSS.TASK_ES));
cpu.segDS.load(cpu.getShort(addrNew + X86.TSS.TASK_DS));
cpu.setCSIP(cpu.getShort(addrNew + X86.TSS.TASK_IP), cpu.getShort(addrNew + X86.TSS.TASK_CS));
if (this.cpl < cplOld) {
offSP = (this.cpl << 2) + X86.TSS.CPL0_SP;
offSS = offSP + 2;
}
cpu.setSS(cpu.getShort(addrNew + offSS), true);
cpu.setSP(cpu.getShort(addrNew + offSP));
cpu.segLDT.load(cpu.getShort(addrNew + X86.TSS.TASK_LDT));
if (fNest) cpu.setShort(addrNew + X86.TSS.PREV_TSS, selOld);
cpu.regCR0 |= X86.CR0.MSW.TS;
return true;
};
/**
* setBase(addr)
*
@ -1008,23 +1016,23 @@ X86Seg.prototype.updateMode = function(fLoad, fProt)
};
/**
* messageSeg(sel, base, limit, acc, ext)
* messageSeg(sel, base, limit, type, ext)
*
* @this {X86Seg}
* @param {number} sel
* @param {number} base
* @param {number} limit
* @param {number} acc
* @param {number} type
* @param {number} [ext]
*/
X86Seg.prototype.messageSeg = function(sel, base, limit, acc, ext)
X86Seg.prototype.messageSeg = function(sel, base, limit, type, ext)
{
if (DEBUG) {
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(Messages.SEG)) {
var ch = (this.sName.length < 3? " " : "");
var sDPL = " dpl=" + this.dpl;
if (this.id == X86Seg.ID.CODE) sDPL += " cpl=" + this.cpl;
this.dbg.message("loadSeg(" + this.sName + "):" + ch + "sel=" + str.toHexWord(sel) + " base=" + str.toHex(base) + " limit=" + str.toHexWord(limit) + " acc=" + str.toHexWord(acc) + sDPL);
this.dbg.message("loadSeg(" + this.sName + "):" + ch + "sel=" + str.toHexWord(sel) + " base=" + str.toHex(base) + " limit=" + str.toHexWord(limit) + " type=" + str.toHexWord(type) + sDPL, true);
}
this.cpu.assert(/* base !== X86.ADDR_INVALID && */ (this.cpu.model >= X86.MODEL_80386 || !ext || ext == X86.DESC.EXT.AVAIL));
}