Conforming code segment correction
This commit is contained in:
parent
6f79a84d83
commit
410bcb60c9
6 changed files with 107 additions and 56 deletions
|
|
@ -3298,7 +3298,7 @@ if (DEBUGGER) {
|
||||||
if (!seg) return;
|
if (!seg) return;
|
||||||
|
|
||||||
var sDump = "";
|
var sDump = "";
|
||||||
var type = seg.type & ~X86.DESC.ACC.TSS_BUSY;
|
var type = seg.type & ~X86.DESC.ACC.TYPE.TSS_BUSY;
|
||||||
var cch = (type == X86.DESC.ACC.TYPE.TSS286? 4 : 8);
|
var cch = (type == X86.DESC.ACC.TYPE.TSS286? 4 : 8);
|
||||||
var aTSSFields = (type == X86.DESC.ACC.TYPE.TSS286? Debugger.TSS286 : Debugger.TSS386);
|
var aTSSFields = (type == X86.DESC.ACC.TYPE.TSS286? Debugger.TSS286 : Debugger.TSS386);
|
||||||
var off, addr, v;
|
var off, addr, v;
|
||||||
|
|
@ -4206,6 +4206,15 @@ if (DEBUGGER) {
|
||||||
}
|
}
|
||||||
this.chipset.acTimer0Counts = [];
|
this.chipset.acTimer0Counts = [];
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (this.messageEnabled(Messages.HALT)) {
|
||||||
|
/*
|
||||||
|
* It's possible the user is trying to 'g' past a fault that was blocked by helpCheckFault()
|
||||||
|
* for the Debugger's benefit; if so, it will continue to be blocked, so try displaying a helpful
|
||||||
|
* message (another helpful tip would be to simply turn off the "halt" message category).
|
||||||
|
*/
|
||||||
|
sStopped += " (use the 't' command to execute blocked faults)";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.println(sStopped);
|
this.println(sStopped);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -219,6 +219,11 @@ var X86 = {
|
||||||
WRITABLE: 0x0200, // DATA: set if writable, clear if read-only
|
WRITABLE: 0x0200, // DATA: set if writable, clear if read-only
|
||||||
CONFORMING: 0x0400, // CODE: set if conforming, clear if not
|
CONFORMING: 0x0400, // CODE: set if conforming, clear if not
|
||||||
EXPDOWN: 0x0400, // DATA: set if expand-down, clear if not
|
EXPDOWN: 0x0400, // DATA: set if expand-down, clear if not
|
||||||
|
/*
|
||||||
|
* Assorted bits that apply only within NONSEG values
|
||||||
|
*/
|
||||||
|
TSS_BUSY: 0x0200,
|
||||||
|
NONSEG_386: 0x0800, // 80386 and up
|
||||||
/*
|
/*
|
||||||
* The following are all the possible (valid) types (well, except for the variations
|
* The following are all the possible (valid) types (well, except for the variations
|
||||||
* of DATA and CODE where the ACCESSED bit (0x0100) may also be set)
|
* of DATA and CODE where the ACCESSED bit (0x0100) may also be set)
|
||||||
|
|
@ -244,11 +249,6 @@ var X86 = {
|
||||||
CODE_CONFORMING: 0x1C00,
|
CODE_CONFORMING: 0x1C00,
|
||||||
CODE_CONFORMING_READABLE: 0x1E00
|
CODE_CONFORMING_READABLE: 0x1E00
|
||||||
},
|
},
|
||||||
/*
|
|
||||||
* Assorted ACC bits within NONSEG values
|
|
||||||
*/
|
|
||||||
TSS_BUSY: 0x0200,
|
|
||||||
NONSEG_386: 0x0800, // 80386 and up
|
|
||||||
DPL: {
|
DPL: {
|
||||||
MASK: 0x6000,
|
MASK: 0x6000,
|
||||||
SHIFT: 13
|
SHIFT: 13
|
||||||
|
|
|
||||||
|
|
@ -2216,7 +2216,7 @@ X86CPU.prototype.setLIP = function(addr)
|
||||||
* never set without an accompanying IP (well, except for a few undocumented instructions, like POP CS, which
|
* never set without an accompanying IP (well, except for a few undocumented instructions, like POP CS, which
|
||||||
* were available ONLY on the 8086/8088/80186/80188; see setCS() for details).
|
* were available ONLY on the 8086/8088/80186/80188; see setCS() for details).
|
||||||
*
|
*
|
||||||
* And even though this function is called setCSIP(), please note the order of the parameters is IP,CS,
|
* And even though this function is called setCSIP(), please note the order of the parameters is [IP,CS],
|
||||||
* which matches the order that CS:IP values are normally stored in memory, allowing us to make calls like this:
|
* which matches the order that CS:IP values are normally stored in memory, allowing us to make calls like this:
|
||||||
*
|
*
|
||||||
* this.setCSIP(this.popWord(), this.popWord());
|
* this.setCSIP(this.popWord(), this.popWord());
|
||||||
|
|
@ -2225,7 +2225,7 @@ X86CPU.prototype.setLIP = function(addr)
|
||||||
* @param {number} off
|
* @param {number} off
|
||||||
* @param {number} sel
|
* @param {number} sel
|
||||||
* @param {boolean} [fCall] is true if CALLF in progress, false if RETF/IRET in progress, undefined otherwise
|
* @param {boolean} [fCall] is true if CALLF in progress, false if RETF/IRET in progress, undefined otherwise
|
||||||
* @return {boolean|null} true if a stack switch occurred; the only opcode that really needs to pay attention is opRETFn()
|
* @return {boolean|null} true if a stack switch occurred; the only operation that needs to pay attention is opRETFn()
|
||||||
*/
|
*/
|
||||||
X86CPU.prototype.setCSIP = function(off, sel, fCall)
|
X86CPU.prototype.setCSIP = function(off, sel, fCall)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1537,8 +1537,8 @@ X86.fnLTR = function(dst, src)
|
||||||
{
|
{
|
||||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||||
if (this.segTSS.load(dst) !== X86.ADDR_INVALID) {
|
if (this.segTSS.load(dst) !== X86.ADDR_INVALID) {
|
||||||
this.setShort(this.segTSS.addrDesc + X86.DESC.ACC.OFFSET, this.segTSS.acc |= X86.DESC.ACC.TSS_BUSY);
|
this.setShort(this.segTSS.addrDesc + X86.DESC.ACC.OFFSET, this.segTSS.acc |= X86.DESC.ACC.TYPE.TSS_BUSY);
|
||||||
this.segTSS.type |= X86.DESC.ACC.TSS_BUSY;
|
this.segTSS.type |= X86.DESC.ACC.TYPE.TSS_BUSY;
|
||||||
}
|
}
|
||||||
this.nStepCycles -= (17 + (this.regEA === X86.ADDR_INVALID? 0 : 2));
|
this.nStepCycles -= (17 + (this.regEA === X86.ADDR_INVALID? 0 : 2));
|
||||||
return dst;
|
return dst;
|
||||||
|
|
|
||||||
|
|
@ -960,7 +960,7 @@ X86.helpCheckFault = function(nFault, nError, fHalt)
|
||||||
|
|
||||||
var fRunning = this.aFlags.fRunning;
|
var fRunning = this.aFlags.fRunning;
|
||||||
var sMessage = "Fault " + str.toHexByte(nFault) + (nError != null? " (" + str.toHexWord(nError) + ")" : "") + " on opcode " + str.toHexByte(bOpcode);
|
var sMessage = "Fault " + str.toHexByte(nFault) + (nError != null? " (" + str.toHexWord(nError) + ")" : "") + " on opcode " + str.toHexByte(bOpcode);
|
||||||
if (fHalt && fRunning) sMessage += " (blocked by PCjs Debugger)";
|
if (fHalt && fRunning) sMessage += " (blocked)";
|
||||||
|
|
||||||
if (DEBUGGER && this.dbg) {
|
if (DEBUGGER && this.dbg) {
|
||||||
this.printMessage(sMessage, fHalt || bitsMessage, true);
|
this.printMessage(sMessage, fHalt || bitsMessage, true);
|
||||||
|
|
|
||||||
|
|
@ -645,7 +645,7 @@ X86Seg.prototype.loadDesc6 = function(addrDesc, sel)
|
||||||
*
|
*
|
||||||
* Probed loads allow us to deal with complex segment load operations (ie, those involving an implied stack-switch
|
* Probed loads allow us to deal with complex segment load operations (ie, those involving an implied stack-switch
|
||||||
* or task-switch), by allowing us to probe all the new selectors and generate the necessary faults before modifying
|
* or task-switch), by allowing us to probe all the new selectors and generate the necessary faults before modifying
|
||||||
* any segment registers; if all the probes succeed, then all the loads can proceed.
|
* any segment registers; if all the probes succeed, then the original load can proceed.
|
||||||
*
|
*
|
||||||
* The next non-probed load of a probed selector will move those probed descriptor values into the X86Seg object,
|
* The next non-probed load of a probed selector will move those probed descriptor values into the X86Seg object,
|
||||||
* saving us from having to reload and reparse the descriptor. However, if a different selector is loaded between
|
* saving us from having to reload and reparse the descriptor. However, if a different selector is loaded between
|
||||||
|
|
@ -705,21 +705,25 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fProbe)
|
||||||
|
|
||||||
case X86Seg.ID.CODE:
|
case X86Seg.ID.CODE:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE: Since we are X86Seg.ID.CODE, we can use this.cpl instead of the more convoluted
|
||||||
|
* this.cpu.segCS.cpl.
|
||||||
|
*/
|
||||||
var fCall = this.fCall;
|
var fCall = this.fCall;
|
||||||
this.fStackSwitch = false;
|
this.fStackSwitch = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This special bit of code is currently used only by the Debugger, when it needs to inject
|
* This special bit of code is currently used only by the Debugger, when it needs to inject
|
||||||
* a 16:32 callback address into the machine that it can intercept calls to. We call these
|
* a 16:32 callback address into the machine that it can intercept calls to. We call these
|
||||||
* "call break" addresses, because they're like private breakpoints that only operate when
|
* "call break" addresses, because they're essentially breakpoints that only operate when
|
||||||
* a particular address is called; specifically, an address with selector 0x0001 and an offset
|
* a particular address is called; specifically, an address with selector 0x0001 and an offset
|
||||||
* that forms an index (1-based) into the aCallBreaks function table.
|
* that forms a (1-based) index into the aCallBreaks function table.
|
||||||
*
|
*
|
||||||
* In protected-mode, 0x0001 is an invalid code selector (a null selector with an RPL of 1),
|
* In protected-mode, any null selector, including 0x0001 (null with an RPL of 1), is
|
||||||
* and while it's not inconceivable that an operating system might use such a selector for
|
* an invalid CS selector, and while it's not inconceivable that an operating system might
|
||||||
* some strange purpose, I've not seen such an operating system. And in any case, those
|
* use such a selector for some strange purpose, I've not seen such an operating system.
|
||||||
* operating systems are not likely to trigger the Debugger's call to addCallBreak(), so no
|
* And in any case, those operating systems are not likely to trigger the Debugger's call to
|
||||||
* call breaks will be generated, and this code will never execute.
|
* addCallBreak(), so no call breaks will be generated, and this code will never execute.
|
||||||
*
|
*
|
||||||
* TODO: If we ever need this to be mode-independent, it can be moved somewhere where it will
|
* TODO: If we ever need this to be mode-independent, it can be moved somewhere where it will
|
||||||
* trigger for both real and protected-mode code segment loads, because CALLBREAK_SEL (0x0001)
|
* trigger for both real and protected-mode code segment loads, because CALLBREAK_SEL (0x0001)
|
||||||
|
|
@ -744,43 +748,81 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fProbe)
|
||||||
|
|
||||||
if (!selMasked) {
|
if (!selMasked) {
|
||||||
/*
|
/*
|
||||||
* selMasked is really the descriptor table offset, and a zero offset is fine for the IDT;
|
* selMasked is really the descriptor table offset, and a zero offset is fine for the IDT,
|
||||||
* it MAY even be OK for the LDT. But it's definitely not OK for the GDT; a null selector
|
* and it's probably fine for the LDT, but it's definitely NOT fine for the GDT, because
|
||||||
* is allowed in any of DS, ES, SS, FS, or GS, but never CS). Since there's no parameter
|
* that's a reference to the null selector. A null selector is allowed in DS, ES, FS, or GS,
|
||||||
* that tells us which table we're using, we have to check manually.
|
* but never CS or SS. Since there's no parameter that tells us which table we're using,
|
||||||
|
* we have to check manually.
|
||||||
*
|
*
|
||||||
* If we ARE attempting to load a null selector from the GDT, then we zero type, which ensures
|
* If we ARE attempting to load a null selector from the GDT, then we zero type, ensuring that
|
||||||
* that sizeGate will remain invalid, triggering a GP_FAULT below.
|
* sizeGate will remain invalid (-1), triggering a GP_FAULT below.
|
||||||
*/
|
*/
|
||||||
if (addrDesc >= cpu.addrGDT && addrDesc < cpu.addrGDTLimit) type = 0;
|
if (addrDesc >= cpu.addrGDT && addrDesc < cpu.addrGDTLimit) type = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Since we are X86Seg.ID.CODE, we can use this.cpl instead of the more generic cpu.segCS.cpl
|
|
||||||
*/
|
|
||||||
if (type >= X86.DESC.ACC.TYPE.CODE_EXECONLY) {
|
if (type >= X86.DESC.ACC.TYPE.CODE_EXECONLY) {
|
||||||
sizeGate = 0;
|
/*
|
||||||
if (rpl > this.cpl) {
|
* There are three basic ways a new code segment can be loaded (ignoring special cases like LOADALL):
|
||||||
/*.
|
*
|
||||||
* If fCall is false, then we must have a RETF to a less privileged segment, which is OK.
|
* 1) CALLF (fCall is true)
|
||||||
|
* 2) RETF (fCall is false)
|
||||||
|
* 3) JMPF (fCall is undefined)
|
||||||
|
*/
|
||||||
|
if (fProbe != null) {
|
||||||
|
sizeGate = 0;
|
||||||
|
}
|
||||||
|
else if (fCall !== false) {
|
||||||
|
/*
|
||||||
|
* We deal with CALLF/JMPF first. We've already ascertained that the selector type refers to
|
||||||
|
* a segment, not a gate, so the next important distinction is CONFORMING vs. non-CONFORMING.
|
||||||
*
|
*
|
||||||
* Otherwise, we must be dealing with a CALLF or JMPF to a less privileged segment, in which
|
* For a CONFORMING target, we must verify that its DPL <= CPL. For a non-CONFORMING target,
|
||||||
* case either DPL == CPL *or* the new segment is conforming and DPL <= CPL.
|
* we must verify that RPL <= CPL and DPL == CPL. Assuming both those tests pass, we must also
|
||||||
|
* ensure that the current CPL is recorded as the new RPL (that is, the RPL bits of sel must be
|
||||||
|
* updated).
|
||||||
*/
|
*/
|
||||||
sizeGate = -1;
|
if (type & X86.DESC.ACC.TYPE.CONFORMING) {
|
||||||
if (fCall === false || dpl == this.cpl || (type & X86.DESC.ACC.TYPE.CONFORMING) && dpl <= this.cpl) {
|
if (dpl <= this.cpl) {
|
||||||
/*
|
sizeGate = 0;
|
||||||
* It's critical that any stack switch occur with the operand size in effect at the time of
|
}
|
||||||
* the current instruction, BEFORE any calls to updateMode() and resetSizes(), otherwise the
|
} else {
|
||||||
* operand size (or operand override) in effect on an instruction like IRETD will be ignored.
|
if (rpl <= this.cpl && dpl == this.cpl) {
|
||||||
*/
|
sizeGate = 0;
|
||||||
regSP = cpu.popWord();
|
}
|
||||||
cpu.setSS(cpu.popWord(), true);
|
}
|
||||||
cpu.setSP(regSP);
|
if (!sizeGate) {
|
||||||
this.fStackSwitch = true;
|
sel = (sel & ~X86.SEL.RPL) | (this.cpl & X86.SEL.RPL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/*
|
||||||
|
* We deal with RETF next. For starters, we must verify that RPL >= CPL. Moreover, if
|
||||||
|
* RPL > CPL, then we have a privilege level change that requires a stack switch, assuming
|
||||||
|
* the stack selector is acceptable.
|
||||||
|
*/
|
||||||
|
if (rpl >= this.cpl) {
|
||||||
|
if (rpl > this.cpl) {
|
||||||
|
regSP = cpu.popWord();
|
||||||
|
cpu.setSS(cpu.popWord(), true);
|
||||||
|
cpu.setSP(regSP);
|
||||||
|
this.fStackSwitch = true;
|
||||||
|
}
|
||||||
sizeGate = 0;
|
sizeGate = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (DEBUG) {
|
||||||
|
var sizeGateCheck = 0, fStackSwitchCheck = false;
|
||||||
|
if (rpl > this.cpl) {
|
||||||
|
sizeGateCheck = -1;
|
||||||
|
if (fCall === false || dpl == this.cpl || (type & X86.DESC.ACC.TYPE.CONFORMING) && dpl <= this.cpl) {
|
||||||
|
fStackSwitchCheck = true;
|
||||||
|
sizeGateCheck = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sizeGate != sizeGateCheck || this.fStackSwitch != fStackSwitchCheck) {
|
||||||
|
this.cpu.stopCPU();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (type == X86.DESC.ACC.TYPE.TSS286 || type == X86.DESC.ACC.TYPE.TSS386) {
|
else if (type == X86.DESC.ACC.TYPE.TSS286 || type == X86.DESC.ACC.TYPE.TSS386) {
|
||||||
if (!this.switchTSS(sel, fCall)) {
|
if (!this.switchTSS(sel, fCall)) {
|
||||||
|
|
@ -851,7 +893,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fProbe)
|
||||||
* TODO: Verify the PRESENT bit of the gate descriptor, and issue NP_FAULT as appropriate.
|
* TODO: Verify the PRESENT bit of the gate descriptor, and issue NP_FAULT as appropriate.
|
||||||
*/
|
*/
|
||||||
selCode = base & 0xffff;
|
selCode = base & 0xffff;
|
||||||
if (I386 && (type & X86.DESC.ACC.NONSEG_386)) {
|
if (I386 && (type & X86.DESC.ACC.TYPE.NONSEG_386)) {
|
||||||
limit = limitOrig | (ext << 16);
|
limit = limitOrig | (ext << 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -878,7 +920,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fProbe)
|
||||||
* and then figure out which should really be used.
|
* and then figure out which should really be used.
|
||||||
*/
|
*/
|
||||||
addrTSS = cpu.segTSS.base;
|
addrTSS = cpu.segTSS.base;
|
||||||
if (!I386 || !(cpu.segTSS.type & X86.DESC.ACC.NONSEG_386)) {
|
if (!I386 || !(cpu.segTSS.type & X86.DESC.ACC.TYPE.NONSEG_386)) {
|
||||||
offSP = (cplNew << 2) + X86.TSS286.CPL0_SP;
|
offSP = (cplNew << 2) + X86.TSS286.CPL0_SP;
|
||||||
lenSP = 2;
|
lenSP = 2;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -925,7 +967,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fProbe)
|
||||||
* TODO: Consider whether we can skip this loadProt() call if this.sel already contains selCode
|
* TODO: Consider whether we can skip this loadProt() call if this.sel already contains selCode
|
||||||
* (and the previous mode matches, which might require we cache the mode in the X86Seg object, too).
|
* (and the previous mode matches, which might require we cache the mode in the X86Seg object, too).
|
||||||
*/
|
*/
|
||||||
if (this.loadProt(selCode) === X86.ADDR_INVALID) {
|
if (this.loadProt(selCode, false) === X86.ADDR_INVALID) {
|
||||||
return X86.ADDR_INVALID;
|
return X86.ADDR_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -933,9 +975,9 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fProbe)
|
||||||
|
|
||||||
this.offIP = limit;
|
this.offIP = limit;
|
||||||
|
|
||||||
cpu.assert(this.cpl == cplNew);
|
// cpu.assert(this.cpl == cplNew);
|
||||||
|
|
||||||
if (this.cpl < cplOld) {
|
if (cplNew < cplOld) {
|
||||||
|
|
||||||
if (fCall !== true) {
|
if (fCall !== true) {
|
||||||
cpu.assert(false);
|
cpu.assert(false);
|
||||||
|
|
@ -1065,7 +1107,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fProbe)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case X86Seg.ID.TSS:
|
case X86Seg.ID.TSS:
|
||||||
var typeTSS = type & ~X86.DESC.ACC.TSS_BUSY;
|
var typeTSS = type & ~X86.DESC.ACC.TYPE.TSS_BUSY;
|
||||||
if (!selMasked || typeTSS != X86.DESC.ACC.TYPE.TSS286 && typeTSS != X86.DESC.ACC.TYPE.TSS386) {
|
if (!selMasked || typeTSS != X86.DESC.ACC.TYPE.TSS286 && typeTSS != X86.DESC.ACC.TYPE.TSS386) {
|
||||||
X86.helpFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel & X86.ERRCODE.SELMASK);
|
X86.helpFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel & X86.ERRCODE.SELMASK);
|
||||||
return X86.ADDR_INVALID;
|
return X86.ADDR_INVALID;
|
||||||
|
|
@ -1180,14 +1222,14 @@ X86Seg.prototype.switchTSS = function switchTSS(selNew, fNest)
|
||||||
/*
|
/*
|
||||||
* TODO: Verify that it is (always) correct to require that the BUSY bit be currently set.
|
* TODO: Verify that it is (always) correct to require that the BUSY bit be currently set.
|
||||||
*/
|
*/
|
||||||
if (!(cpu.segTSS.type & X86.DESC.ACC.TSS_BUSY)) {
|
if (!(cpu.segTSS.type & X86.DESC.ACC.TYPE.TSS_BUSY)) {
|
||||||
X86.helpFault.call(cpu, X86.EXCEPTION.GP_FAULT, selNew & X86.ERRCODE.SELMASK);
|
X86.helpFault.call(cpu, X86.EXCEPTION.GP_FAULT, selNew & X86.ERRCODE.SELMASK);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* TODO: Should I be more paranoid about writing our cached ACC value back into the descriptor?
|
* TODO: Should I be more paranoid about writing our cached ACC value back into the descriptor?
|
||||||
*/
|
*/
|
||||||
cpu.setShort(cpu.segTSS.addrDesc + X86.DESC.ACC.OFFSET, cpu.segTSS.acc &= ~X86.DESC.ACC.TSS_BUSY);
|
cpu.setShort(cpu.segTSS.addrDesc + X86.DESC.ACC.OFFSET, cpu.segTSS.acc &= ~X86.DESC.ACC.TYPE.TSS_BUSY);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cpu.segTSS.load(selNew) === X86.ADDR_INVALID) {
|
if (cpu.segTSS.load(selNew) === X86.ADDR_INVALID) {
|
||||||
|
|
@ -1200,18 +1242,18 @@ X86Seg.prototype.switchTSS = function switchTSS(selNew, fNest)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fNest !== false) {
|
if (fNest !== false) {
|
||||||
if (cpu.segTSS.type & X86.DESC.ACC.TSS_BUSY) {
|
if (cpu.segTSS.type & X86.DESC.ACC.TYPE.TSS_BUSY) {
|
||||||
X86.helpFault.call(cpu, X86.EXCEPTION.GP_FAULT, selNew & X86.ERRCODE.SELMASK);
|
X86.helpFault.call(cpu, X86.EXCEPTION.GP_FAULT, selNew & X86.ERRCODE.SELMASK);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
cpu.setShort(cpu.segTSS.addrDesc + X86.DESC.ACC.OFFSET, cpu.segTSS.acc |= X86.DESC.ACC.TSS_BUSY);
|
cpu.setShort(cpu.segTSS.addrDesc + X86.DESC.ACC.OFFSET, cpu.segTSS.acc |= X86.DESC.ACC.TYPE.TSS_BUSY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now that we're done checking the TSS_BUSY bit in the TYPE field (which is a subset of the ACC field),
|
* Now that we're done checking the TSS_BUSY bit in the TYPE field (which is a subset of the ACC field),
|
||||||
* sync any changes made above in the ACC field to the TYPE field.
|
* sync any changes made above in the ACC field to the TYPE field.
|
||||||
*/
|
*/
|
||||||
cpu.segTSS.type = (cpu.segTSS.type & ~X86.DESC.ACC.TSS_BUSY) | (cpu.segTSS.acc & X86.DESC.ACC.TSS_BUSY);
|
cpu.segTSS.type = (cpu.segTSS.type & ~X86.DESC.ACC.TYPE.TSS_BUSY) | (cpu.segTSS.acc & X86.DESC.ACC.TYPE.TSS_BUSY);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update the old TSS
|
* Update the old TSS
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue