Removed fSuppress hack from general-purpose segment register operations
This commit is contained in:
parent
712ecb7eaf
commit
a3f1df0ba7
4 changed files with 134 additions and 85 deletions
|
|
@ -1358,7 +1358,7 @@ if (DEBUGGER) {
|
|||
/*
|
||||
* Allocate a special segment "register" for our own use, whenever a requested selector is not currently loaded
|
||||
*/
|
||||
this.segDebugger = new X86Seg(this.cpu, X86Seg.ID.DEBUG, "DBG");
|
||||
this.segDebugger = new X86Seg(this.cpu, X86Seg.ID.DBG, "DBG");
|
||||
|
||||
this.aaOpDescs = Debugger.aaOpDescs;
|
||||
if (this.cpu.model >= X86.MODEL_80186) {
|
||||
|
|
@ -1531,21 +1531,16 @@ if (DEBUGGER) {
|
|||
if (sel === this.cpu.getGS()) return this.cpu.segGS;
|
||||
}
|
||||
/*
|
||||
* Even if nSuppressBreaks is set, we'll allow the call if we're in real-mode, because
|
||||
* a loadReal() request using segDebugger should generally be safe.
|
||||
* Even if nSuppressBreaks is set, we'll allow the call in real-mode,
|
||||
* because a loadReal() request using segDebugger should generally be safe.
|
||||
*/
|
||||
if (this.nSuppressBreaks && fProt || !this.segDebugger) return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note the load() function's fSuppress parameter, which the Debugger should ALWAYS set to true
|
||||
* to avoid triggering a fault. Unfortunately, when paging is enabled, there's still the risk of
|
||||
* triggering a page fault that will alter the machine's state, so be careful.
|
||||
*/
|
||||
if (!fProt) {
|
||||
this.segDebugger.loadReal(sel, true);
|
||||
this.segDebugger.loadReal(sel);
|
||||
} else {
|
||||
this.segDebugger.loadProt(sel, true);
|
||||
this.segDebugger.loadProt(sel);
|
||||
}
|
||||
return this.segDebugger;
|
||||
};
|
||||
|
|
@ -1574,9 +1569,9 @@ if (DEBUGGER) {
|
|||
var seg = this.getSegment(dbgAddr.sel, dbgAddr.fProt);
|
||||
if (seg) {
|
||||
if (!fWrite) {
|
||||
addr = seg.checkRead(dbgAddr.off, nb || 1, true);
|
||||
addr = seg.checkReadDebugger(dbgAddr.off || 0, nb || 1);
|
||||
} else {
|
||||
addr = seg.checkWrite(dbgAddr.off, nb || 1, true);
|
||||
addr = seg.checkWriteDebugger(dbgAddr.off || 0, nb || 1);
|
||||
}
|
||||
dbgAddr.addr = addr;
|
||||
}
|
||||
|
|
@ -3265,7 +3260,8 @@ if (DEBUGGER) {
|
|||
Debugger.prototype.addBreakpoint = function(aBreak, dbgAddr, fTempBreak)
|
||||
{
|
||||
var fSuccess = false;
|
||||
this.nSuppressBreaks++;
|
||||
|
||||
// this.nSuppressBreaks++;
|
||||
|
||||
/*
|
||||
* We need to allow a temporary breakpoint at an address where they may already be a breakpoint.
|
||||
|
|
@ -3277,6 +3273,7 @@ if (DEBUGGER) {
|
|||
if (aBreak != this.aBreakExec) {
|
||||
var addr = this.getAddr(dbgAddr);
|
||||
if (addr == X86.ADDR_INVALID) {
|
||||
this.println("invalid address: " + this.hexAddr(dbgAddr));
|
||||
fSuccess = false;
|
||||
} else {
|
||||
this.bus.addMemBreak(addr, aBreak == this.aBreakWrite);
|
||||
|
|
@ -3306,7 +3303,8 @@ if (DEBUGGER) {
|
|||
}
|
||||
}
|
||||
|
||||
this.nSuppressBreaks--;
|
||||
// this.nSuppressBreaks--;
|
||||
|
||||
return fSuccess;
|
||||
};
|
||||
|
||||
|
|
@ -3454,6 +3452,7 @@ if (DEBUGGER) {
|
|||
* or history data (see checkInstruction), since we might not actually execute the current instruction.
|
||||
*/
|
||||
var fBreak = false;
|
||||
|
||||
if (!this.nSuppressBreaks++) {
|
||||
|
||||
addr = this.mapBreakpoint(addr);
|
||||
|
|
@ -3545,7 +3544,9 @@ if (DEBUGGER) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.nSuppressBreaks--;
|
||||
|
||||
return fBreak;
|
||||
};
|
||||
|
||||
|
|
@ -5791,6 +5792,11 @@ if (DEBUGGER) {
|
|||
case "DI":
|
||||
this.cpu.regEDI = (this.cpu.regEDI & ~0xffff) | (w & 0xffff);
|
||||
break;
|
||||
/*
|
||||
* DANGER: For any of the segment loads below, by going through the normal CPU
|
||||
* segment load procedure, you run the risk of generating a fault in the machine
|
||||
* if you're not careful. So, um, be careful.
|
||||
*/
|
||||
case "DS":
|
||||
this.cpu.setDS(w);
|
||||
break;
|
||||
|
|
@ -5852,7 +5858,12 @@ if (DEBUGGER) {
|
|||
this.cpu.setMSW(w);
|
||||
break;
|
||||
case "TR":
|
||||
if (this.cpu.segTSS.load(w, true) === X86.ADDR_INVALID) {
|
||||
/*
|
||||
* DANGER: Like any of the segment loads above, by going through the normal CPU
|
||||
* segment load procedure, you run the risk of generating a fault in the machine
|
||||
* if you're not careful. So, um, be careful.
|
||||
*/
|
||||
if (this.cpu.segTSS.load(w) === X86.ADDR_INVALID) {
|
||||
fValid = false;
|
||||
}
|
||||
break;
|
||||
|
|
@ -5889,6 +5900,11 @@ if (DEBUGGER) {
|
|||
case "EDI":
|
||||
this.cpu.regEDI = w;
|
||||
break;
|
||||
/*
|
||||
* DANGER: For any of the segment loads below, by going through the normal CPU
|
||||
* segment load procedure, you run the risk of generating a fault in the machine
|
||||
* if you're not careful. So, um, be careful.
|
||||
*/
|
||||
case "FS":
|
||||
this.cpu.setFS(w);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1400,9 +1400,9 @@ X86CPU.prototype.resetRegs = function()
|
|||
* TODO: Verify what the 80286 actually sets addrGDT and addrGDTLimit to on reset (or if it leaves them alone).
|
||||
*/
|
||||
this.addrGDT = 0; this.addrGDTLimit = 0xffff; // GDTR
|
||||
this.segLDT = new X86Seg(this, X86Seg.ID.LDT, "LDT", true); // LDTR
|
||||
this.segTSS = new X86Seg(this, X86Seg.ID.TSS, "TSS", true); // TR
|
||||
this.segVER = new X86Seg(this, X86Seg.ID.OTHER, "VER", true); // a scratch segment register for VERR and VERW instructions
|
||||
this.segLDT = new X86Seg(this, X86Seg.ID.LDT, "LDT", true); // LDTR
|
||||
this.segTSS = new X86Seg(this, X86Seg.ID.TSS, "TSS", true); // TR
|
||||
this.segVER = new X86Seg(this, X86Seg.ID.VER, "VER", true); // a scratch segment register for VERR and VERW instructions
|
||||
this.setCSIP(0xfff0, 0xf000); // on an 80286 or 80386, the default CS:IP is 0xF000:0xFFF0 instead of 0xFFFF:0x0000
|
||||
this.setCSBase(0xffff0000|0); // on an 80286 or 80386, all CS base address bits above bit 15 must be set
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1396,7 +1396,7 @@ X86.fnLAR = function LAR(dst, src)
|
|||
* if we need a special check for them.
|
||||
*/
|
||||
this.clearZF();
|
||||
if (this.segVER.load(src, true) !== X86.ADDR_INVALID) {
|
||||
if (this.segVER.load(src) !== X86.ADDR_INVALID) {
|
||||
if (this.segVER.dpl >= this.nCPL && this.segVER.dpl >= (src & X86.SEL.RPL)) {
|
||||
this.setZF();
|
||||
dst = this.segVER.acc & ~X86.DESC.ACC.BASE1623;
|
||||
|
|
@ -1700,7 +1700,7 @@ X86.fnLSL = function LSL(dst, src)
|
|||
* TODO: LSL is explicitly documented as ALSO requiring a non-null selector, so we check X86.SEL.MASK;
|
||||
* are there any other instructions that were, um, less explicit but also require a non-null selector?
|
||||
*/
|
||||
if ((src & X86.SEL.MASK) && this.segVER.load(src, true) !== X86.ADDR_INVALID) {
|
||||
if ((src & X86.SEL.MASK) && this.segVER.load(src) !== X86.ADDR_INVALID) {
|
||||
var fConforming = ((this.segVER.acc & X86.DESC.ACC.TYPE.CODE_CONFORMING) == X86.DESC.ACC.TYPE.CODE_CONFORMING);
|
||||
if ((fConforming || this.segVER.dpl >= this.nCPL) && this.segVER.dpl >= (src & X86.SEL.RPL)) {
|
||||
this.setZF();
|
||||
|
|
@ -3346,7 +3346,7 @@ X86.fnVERR = function VERR(dst, src)
|
|||
* descriptor table or the descriptor is not for a segment.
|
||||
*/
|
||||
this.nStepCycles -= (14 + (this.regEA === X86.ADDR_INVALID? 0 : 2));
|
||||
if (this.segVER.load(dst, true) !== X86.ADDR_INVALID) {
|
||||
if (this.segVER.load(dst) !== X86.ADDR_INVALID) {
|
||||
/*
|
||||
* Verify that this is a readable segment; that is, of these four combinations (code+readable,
|
||||
* code+nonreadable, data+writable, date+nonwritable), make sure we're not the second combination.
|
||||
|
|
@ -3388,7 +3388,7 @@ X86.fnVERW = function VERW(dst, src)
|
|||
* descriptor table or the descriptor is not for a segment.
|
||||
*/
|
||||
this.nStepCycles -= (14 + (this.regEA === X86.ADDR_INVALID? 0 : 2));
|
||||
if (this.segVER.load(dst, true) !== X86.ADDR_INVALID) {
|
||||
if (this.segVER.load(dst) !== X86.ADDR_INVALID) {
|
||||
/*
|
||||
* Verify that this is a writable data segment
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -131,21 +131,20 @@ X86Seg.ID = {
|
|||
STACK: 3, // "SS"
|
||||
TSS: 4, // "TSS"
|
||||
LDT: 5, // "LDT"
|
||||
OTHER: 6, // "VER"
|
||||
DEBUG: 7 // "DBG"
|
||||
VER: 6, // "VER"
|
||||
DBG: 7 // "DBG"
|
||||
};
|
||||
|
||||
/**
|
||||
* loadReal(sel, fSuppress)
|
||||
* loadReal(sel)
|
||||
*
|
||||
* The default segment load() function for real-mode.
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @param {number} sel
|
||||
* @param {boolean} [fSuppress] is true to suppress any errors
|
||||
* @return {number} base address of selected segment, or ADDR_INVALID if error (TODO: No error conditions yet)
|
||||
*/
|
||||
X86Seg.prototype.loadReal = function loadReal(sel, fSuppress)
|
||||
X86Seg.prototype.loadReal = function loadReal(sel)
|
||||
{
|
||||
this.sel = sel & 0xffff;
|
||||
/*
|
||||
|
|
@ -159,7 +158,7 @@ X86Seg.prototype.loadReal = function loadReal(sel, fSuppress)
|
|||
};
|
||||
|
||||
/**
|
||||
* loadProt(sel, fSuppress)
|
||||
* loadProt(sel)
|
||||
*
|
||||
* This replaces the segment's default load() function whenever the segment is notified via updateMode() by the
|
||||
* CPU's setProtMode() that the processor is now in protected-mode.
|
||||
|
|
@ -178,10 +177,9 @@ X86Seg.prototype.loadReal = function loadReal(sel, fSuppress)
|
|||
*
|
||||
* @this {X86Seg}
|
||||
* @param {number} sel
|
||||
* @param {boolean} [fSuppress] is true to suppress any errors, cycle assessment, etc
|
||||
* @return {number} base address of selected segment, or ADDR_INVALID if error
|
||||
*/
|
||||
X86Seg.prototype.loadProt = function loadProt(sel, fSuppress)
|
||||
X86Seg.prototype.loadProt = function loadProt(sel)
|
||||
{
|
||||
var addrDT;
|
||||
var addrDTLimit;
|
||||
|
|
@ -204,11 +202,10 @@ X86Seg.prototype.loadProt = function loadProt(sel, fSuppress)
|
|||
* The ROM BIOS POST executes some test code in protected-mode without properly initializing the LDT,
|
||||
* which has no bearing on the ROM's own code, because it never loads any LDT selectors, but if at the same
|
||||
* time our Debugger attempts to validate a selector in one of its breakpoints, that could cause some
|
||||
* grief here. We avoid that grief by 1) relying on the Debugger setting fSuppress to true, and 2) skipping
|
||||
* segment lookup if the descriptor table being referenced is zero. Both tests are required, because
|
||||
* there's nothing in the design of the CPU that prevents the GDT or LDT being at linear address zero.
|
||||
* grief here. We avoid that grief by skipping segment lookup if the descriptor table being referenced is zero
|
||||
* AND the Debugger's ID.DBG segment register is being used.
|
||||
*/
|
||||
if (!fSuppress || addrDT) {
|
||||
if (addrDT || this.id != X86Seg.ID.DBG) {
|
||||
var addrDesc = (addrDT + (sel & X86.SEL.MASK))|0;
|
||||
if ((addrDTLimit - addrDesc)|0 >= 7) {
|
||||
/*
|
||||
|
|
@ -217,10 +214,10 @@ X86Seg.prototype.loadProt = function loadProt(sel, fSuppress)
|
|||
* starting with a 15-cycle difference. Obviously the difference will vary with the instruction,
|
||||
* and will be much greater whenever the load fails.
|
||||
*/
|
||||
if (!fSuppress) cpu.nStepCycles -= 15;
|
||||
return this.loadDesc8(addrDesc, sel, fSuppress);
|
||||
if (this.id != X86Seg.ID.DBG) cpu.nStepCycles -= 15;
|
||||
return this.loadDesc8(addrDesc, sel);
|
||||
}
|
||||
if (!fSuppress) {
|
||||
if (this.id < X86Seg.ID.VER) {
|
||||
X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel);
|
||||
}
|
||||
}
|
||||
|
|
@ -278,7 +275,7 @@ X86Seg.prototype.loadIDTProt = function loadIDTProt(nIDT)
|
|||
};
|
||||
|
||||
/**
|
||||
* checkReadReal(off, cb, fSuppress)
|
||||
* checkReadReal(off, cb)
|
||||
*
|
||||
* TODO: Invoke X86.fnFault.call(this.cpu, X86.EXCEPTION.GP_FAULT) if off+cb is beyond offMax on 80186 and up;
|
||||
* also, determine whether fnFault() call should include an error code, since this is happening in real-mode.
|
||||
|
|
@ -286,16 +283,15 @@ X86Seg.prototype.loadIDTProt = function loadIDTProt(nIDT)
|
|||
* @this {X86Seg}
|
||||
* @param {number} off is a segment-relative offset
|
||||
* @param {number} cb is number of bytes to check (1, 2 or 4)
|
||||
* @param {boolean} [fSuppress] is true to suppress any errors
|
||||
* @return {number} corresponding linear address if valid, or ADDR_INVALID if error (TODO: No error conditions yet)
|
||||
*/
|
||||
X86Seg.prototype.checkReadReal = function checkReadReal(off, cb, fSuppress)
|
||||
X86Seg.prototype.checkReadReal = function checkReadReal(off, cb)
|
||||
{
|
||||
return (this.base + off)|0;
|
||||
};
|
||||
|
||||
/**
|
||||
* checkWriteReal(off, cb, fSuppress)
|
||||
* checkWriteReal(off, cb)
|
||||
*
|
||||
* TODO: Invoke X86.fnFault.call(this.cpu, X86.EXCEPTION.GP_FAULT) if off+cb is beyond offMax on 80186 and up;
|
||||
* also, determine whether fnFault() call should include an error code, since this is happening in real-mode.
|
||||
|
|
@ -303,24 +299,22 @@ X86Seg.prototype.checkReadReal = function checkReadReal(off, cb, fSuppress)
|
|||
* @this {X86Seg}
|
||||
* @param {number} off is a segment-relative offset
|
||||
* @param {number} cb is number of bytes to check (1, 2 or 4)
|
||||
* @param {boolean} [fSuppress] is true to suppress any errors
|
||||
* @return {number} corresponding linear address if valid, or ADDR_INVALID if error (TODO: No error conditions yet)
|
||||
*/
|
||||
X86Seg.prototype.checkWriteReal = function checkWriteReal(off, cb, fSuppress)
|
||||
X86Seg.prototype.checkWriteReal = function checkWriteReal(off, cb)
|
||||
{
|
||||
return (this.base + off)|0;
|
||||
};
|
||||
|
||||
/**
|
||||
* checkReadProt(off, cb, fSuppress)
|
||||
* checkReadProt(off, cb)
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @param {number} off is a segment-relative offset
|
||||
* @param {number} cb is number of bytes to check (1, 2 or 4)
|
||||
* @param {boolean} [fSuppress] is true to suppress any errors
|
||||
* @return {number} corresponding linear address if valid, or ADDR_INVALID if not
|
||||
*/
|
||||
X86Seg.prototype.checkReadProt = function checkReadProt(off, cb, fSuppress)
|
||||
X86Seg.prototype.checkReadProt = function checkReadProt(off, cb)
|
||||
{
|
||||
/*
|
||||
* Since off could be a 32-bit value with the sign bit (bit 31) set, we must convert
|
||||
|
|
@ -329,19 +323,18 @@ X86Seg.prototype.checkReadProt = function checkReadProt(off, cb, fSuppress)
|
|||
if ((off >>> 0) + cb <= this.offMax) {
|
||||
return (this.base + off)|0;
|
||||
}
|
||||
return this.checkReadProtDisallowed(off, cb, fSuppress);
|
||||
return this.checkReadProtDisallowed(off, cb);
|
||||
};
|
||||
|
||||
/**
|
||||
* checkReadProtDown(off, cb, fSuppress)
|
||||
* checkReadProtDown(off, cb)
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @param {number} off is a segment-relative offset
|
||||
* @param {number} cb is number of bytes to check (1, 2 or 4)
|
||||
* @param {boolean} [fSuppress] is true to suppress any errors
|
||||
* @return {number} corresponding linear address if valid, ADDR_INVALID if not
|
||||
*/
|
||||
X86Seg.prototype.checkReadProtDown = function checkReadProtDown(off, cb, fSuppress)
|
||||
X86Seg.prototype.checkReadProtDown = function checkReadProtDown(off, cb)
|
||||
{
|
||||
/*
|
||||
* Since off could be a 32-bit value with the sign bit (bit 31) set, we must convert
|
||||
|
|
@ -350,81 +343,117 @@ X86Seg.prototype.checkReadProtDown = function checkReadProtDown(off, cb, fSuppre
|
|||
if ((off >>> 0) + cb > this.offMax) {
|
||||
return (this.base + off)|0;
|
||||
}
|
||||
return this.checkReadProtDisallowed(off, cb, fSuppress);
|
||||
return this.checkReadProtDisallowed(off, cb);
|
||||
};
|
||||
|
||||
/**
|
||||
* checkReadProtDisallowed(off, cb, fSuppress)
|
||||
* checkReadProtDisallowed(off, cb)
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @param {number} off is a segment-relative offset
|
||||
* @param {number} cb is number of bytes to check (1, 2 or 4)
|
||||
* @param {boolean} [fSuppress] is true to suppress any errors
|
||||
* @return {number} corresponding linear address if valid, ADDR_INVALID if not
|
||||
*/
|
||||
X86Seg.prototype.checkReadProtDisallowed = function checkReadProtDisallowed(off, cb, fSuppress)
|
||||
X86Seg.prototype.checkReadProtDisallowed = function checkReadProtDisallowed(off, cb)
|
||||
{
|
||||
if (!fSuppress) {
|
||||
X86.fnFault.call(this.cpu, X86.EXCEPTION.GP_FAULT, 0);
|
||||
X86.fnFault.call(this.cpu, X86.EXCEPTION.GP_FAULT, 0);
|
||||
return X86.ADDR_INVALID;
|
||||
};
|
||||
|
||||
/**
|
||||
* checkWriteProt(off, cb)
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @param {number} off is a segment-relative offset
|
||||
* @param {number} cb is number of bytes to check (1, 2 or 4)
|
||||
* @return {number} corresponding linear address if valid, ADDR_INVALID if not
|
||||
*/
|
||||
X86Seg.prototype.checkWriteProt = function checkWriteProt(off, cb)
|
||||
{
|
||||
/*
|
||||
* Since off could be a 32-bit value with the sign bit (bit 31) set, we must convert
|
||||
* it to an unsigned value using ">>>"; offMax was already converted at segment load time.
|
||||
*/
|
||||
if ((off >>> 0) + cb <= this.offMax) {
|
||||
return (this.base + off)|0;
|
||||
}
|
||||
return this.checkWriteProtDisallowed(off, cb);
|
||||
};
|
||||
|
||||
/**
|
||||
* checkWriteProtDown(off, cb)
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @param {number} off is a segment-relative offset
|
||||
* @param {number} cb is number of bytes to check (1, 2 or 4)
|
||||
* @return {number} corresponding linear address if valid, ADDR_INVALID if not
|
||||
*/
|
||||
X86Seg.prototype.checkWriteProtDown = function checkWriteProtDown(off, cb)
|
||||
{
|
||||
/*
|
||||
* Since off could be a 32-bit value with the sign bit (bit 31) set, we must convert
|
||||
* it to an unsigned value using ">>>"; offMax was already converted at segment load time.
|
||||
*/
|
||||
if ((off >>> 0) + cb > this.offMax) {
|
||||
return (this.base + off)|0;
|
||||
}
|
||||
return this.checkWriteProtDisallowed(off, cb);
|
||||
};
|
||||
|
||||
/**
|
||||
* checkWriteProtDisallowed(off, cb)
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @param {number} off is a segment-relative offset
|
||||
* @param {number} cb is number of bytes to check (1, 2 or 4)
|
||||
* @return {number} corresponding linear address if valid, ADDR_INVALID if not
|
||||
*/
|
||||
X86Seg.prototype.checkWriteProtDisallowed = function checkWriteProtDisallowed(off, cb)
|
||||
{
|
||||
X86.fnFault.call(this.cpu, X86.EXCEPTION.GP_FAULT, 0);
|
||||
return X86.ADDR_INVALID;
|
||||
};
|
||||
|
||||
/**
|
||||
* checkReadDebugger(off, cb)
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @param {number} off is a segment-relative offset
|
||||
* @param {number} cb is number of bytes to check (1, 2 or 4)
|
||||
* @return {number} corresponding linear address if valid, or ADDR_INVALID if error
|
||||
*/
|
||||
X86Seg.prototype.checkReadDebugger = function checkReadDebugger(off, cb)
|
||||
{
|
||||
/*
|
||||
* The Debugger doesn't have separate "check" interfaces for real and protected mode,
|
||||
* since it's not performance-critical. If addrDesc is invalid, then we assume real mode.
|
||||
*/
|
||||
if (DEBUGGER) {
|
||||
if (this.addrDesc === X86.ADDR_INVALID || (off >>> 0) + cb <= this.offMax) {
|
||||
return (this.base + off)|0;
|
||||
}
|
||||
}
|
||||
return X86.ADDR_INVALID;
|
||||
};
|
||||
|
||||
/**
|
||||
* checkWriteProt(off, cb, fSuppress)
|
||||
* checkWriteDebugger(off, cb)
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @param {number} off is a segment-relative offset
|
||||
* @param {number} cb is number of bytes to check (1, 2 or 4)
|
||||
* @param {boolean} [fSuppress] is true to suppress any errors
|
||||
* @return {number} corresponding linear address if valid, ADDR_INVALID if not
|
||||
* @return {number} corresponding linear address if valid, or ADDR_INVALID if error
|
||||
*/
|
||||
X86Seg.prototype.checkWriteProt = function checkWriteProt(off, cb, fSuppress)
|
||||
X86Seg.prototype.checkWriteDebugger = function checkWriteDebugger(off, cb)
|
||||
{
|
||||
/*
|
||||
* Since off could be a 32-bit value with the sign bit (bit 31) set, we must convert
|
||||
* it to an unsigned value using ">>>"; offMax was already converted at segment load time.
|
||||
* The Debugger doesn't have separate "check" interfaces for real and protected mode,
|
||||
* since it's not performance-critical. If addrDesc is invalid, then we assume real mode.
|
||||
*/
|
||||
if ((off >>> 0) + cb <= this.offMax) {
|
||||
return (this.base + off)|0;
|
||||
}
|
||||
return this.checkWriteProtDisallowed(off, cb, fSuppress);
|
||||
};
|
||||
|
||||
/**
|
||||
* checkWriteProtDown(off, cb, fSuppress)
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @param {number} off is a segment-relative offset
|
||||
* @param {number} cb is number of bytes to check (1, 2 or 4)
|
||||
* @param {boolean} [fSuppress] is true to suppress any errors
|
||||
* @return {number} corresponding linear address if valid, ADDR_INVALID if not
|
||||
*/
|
||||
X86Seg.prototype.checkWriteProtDown = function checkWriteProtDown(off, cb, fSuppress)
|
||||
{
|
||||
/*
|
||||
* Since off could be a 32-bit value with the sign bit (bit 31) set, we must convert
|
||||
* it to an unsigned value using ">>>"; offMax was already converted at segment load time.
|
||||
*/
|
||||
if ((off >>> 0) + cb > this.offMax) {
|
||||
return (this.base + off)|0;
|
||||
}
|
||||
return this.checkWriteProtDisallowed(off, cb, fSuppress);
|
||||
};
|
||||
|
||||
/**
|
||||
* checkWriteProtDisallowed(off, cb, fSuppress)
|
||||
*
|
||||
* @this {X86Seg}
|
||||
* @param {number} off is a segment-relative offset
|
||||
* @param {number} cb is number of bytes to check (1, 2 or 4)
|
||||
* @param {boolean} [fSuppress] is true to suppress any errors
|
||||
* @return {number} corresponding linear address if valid, ADDR_INVALID if not
|
||||
*/
|
||||
X86Seg.prototype.checkWriteProtDisallowed = function checkWriteProtDisallowed(off, cb, fSuppress)
|
||||
{
|
||||
if (!fSuppress) {
|
||||
X86.fnFault.call(this.cpu, X86.EXCEPTION.GP_FAULT, 0);
|
||||
if (DEBUGGER) {
|
||||
if (this.addrDesc === X86.ADDR_INVALID || (off >>> 0) + cb <= this.offMax) {
|
||||
return (this.base + off)|0;
|
||||
}
|
||||
}
|
||||
return X86.ADDR_INVALID;
|
||||
};
|
||||
|
|
@ -491,13 +520,13 @@ X86Seg.prototype.loadDesc6 = function(addrDesc, sel)
|
|||
this.addrDesc = addrDesc;
|
||||
this.updateMode(true);
|
||||
|
||||
this.messageSeg(sel, base, limit, this.type);
|
||||
if (DEBUG) this.messageSeg(sel, base, limit, this.type);
|
||||
|
||||
return base;
|
||||
};
|
||||
|
||||
/**
|
||||
* loadDesc8(addrDesc, sel, fSuppress)
|
||||
* loadDesc8(addrDesc, sel)
|
||||
*
|
||||
* Used to load a protected-mode selector that refers to an 8-byte "descriptor table" (GDT, LDT, IDT) entry:
|
||||
*
|
||||
|
|
@ -511,10 +540,9 @@ X86Seg.prototype.loadDesc6 = function(addrDesc, sel)
|
|||
* @this {X86Seg}
|
||||
* @param {number} addrDesc is the descriptor address
|
||||
* @param {number} sel is the associated selector, or nIDT*8 if IDT descriptor
|
||||
* @param {boolean} [fSuppress] is true to suppress any errors, cycle assessment, etc
|
||||
* @return {number} base address of selected segment, or ADDR_INVALID if error
|
||||
*/
|
||||
X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
|
||||
X86Seg.prototype.loadDesc8 = function(addrDesc, sel)
|
||||
{
|
||||
var cpu = this.cpu;
|
||||
var limit = cpu.getShort(addrDesc + X86.DESC.LIMIT.OFFSET);
|
||||
|
|
@ -547,7 +575,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
|
|||
var dpl = (acc & X86.DESC.ACC.DPL.MASK) >> X86.DESC.ACC.DPL.SHIFT;
|
||||
|
||||
if (selMasked && !(acc & X86.DESC.ACC.PRESENT)) {
|
||||
if (!fSuppress) X86.fnFault.call(cpu, X86.EXCEPTION.NP_FAULT, sel);
|
||||
if (this.id < X86Seg.ID.VER) X86.fnFault.call(cpu, X86.EXCEPTION.NP_FAULT, sel);
|
||||
base = addrDesc = X86.ADDR_INVALID;
|
||||
break;
|
||||
}
|
||||
|
|
@ -698,13 +726,13 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
|
|||
return this.base;
|
||||
}
|
||||
cpu.assert(false);
|
||||
if (!fSuppress) X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, nFaultError, true);
|
||||
if (this.id < X86Seg.ID.VER) X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, nFaultError, true);
|
||||
base = addrDesc = X86.ADDR_INVALID;
|
||||
break;
|
||||
}
|
||||
else if (fGate !== false) {
|
||||
cpu.assert(false);
|
||||
if (!fSuppress) X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel, true);
|
||||
if (this.id < X86Seg.ID.VER) X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel, true);
|
||||
base = addrDesc = X86.ADDR_INVALID;
|
||||
break;
|
||||
}
|
||||
|
|
@ -712,7 +740,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
|
|||
else if (this.id == X86Seg.ID.DATA) {
|
||||
if (selMasked) {
|
||||
if (!(acc & X86.DESC.ACC.PRESENT)) {
|
||||
if (!fSuppress) X86.fnFault.call(cpu, X86.EXCEPTION.NP_FAULT, sel);
|
||||
if (this.id < X86Seg.ID.VER) X86.fnFault.call(cpu, X86.EXCEPTION.NP_FAULT, sel);
|
||||
base = addrDesc = X86.ADDR_INVALID;
|
||||
break;
|
||||
}
|
||||
|
|
@ -738,7 +766,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
|
|||
*
|
||||
* So, if the ACC field is zero, we won't set the last fnFault() parameter (fHalt) to true.
|
||||
*/
|
||||
if (!fSuppress) X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel, !!acc);
|
||||
if (this.id < X86Seg.ID.VER) X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel, !!acc);
|
||||
base = addrDesc = X86.ADDR_INVALID;
|
||||
break;
|
||||
}
|
||||
|
|
@ -746,12 +774,12 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
|
|||
}
|
||||
else if (this.id == X86Seg.ID.STACK) {
|
||||
if (!(acc & X86.DESC.ACC.PRESENT)) {
|
||||
if (!fSuppress) X86.fnFault.call(cpu, X86.EXCEPTION.SS_FAULT, sel);
|
||||
if (this.id < X86Seg.ID.VER) X86.fnFault.call(cpu, X86.EXCEPTION.SS_FAULT, sel);
|
||||
base = addrDesc = X86.ADDR_INVALID;
|
||||
break;
|
||||
}
|
||||
if (!selMasked || type < X86.DESC.ACC.TYPE.SEG || (type & (X86.DESC.ACC.TYPE.CODE | X86.DESC.ACC.TYPE.WRITABLE)) != X86.DESC.ACC.TYPE.WRITABLE) {
|
||||
if (!fSuppress) X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel, true);
|
||||
if (this.id < X86Seg.ID.VER) X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel, true);
|
||||
base = addrDesc = X86.ADDR_INVALID;
|
||||
break;
|
||||
}
|
||||
|
|
@ -759,7 +787,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
|
|||
else if (this.id == X86Seg.ID.TSS) {
|
||||
var typeTSS = type & ~X86.DESC.ACC.TSS_BUSY;
|
||||
if (!selMasked || typeTSS != X86.DESC.ACC.TYPE.TSS286 && typeTSS != X86.DESC.ACC.TYPE.TSS386) {
|
||||
if (!fSuppress) X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel, true);
|
||||
if (this.id < X86Seg.ID.VER) X86.fnFault.call(cpu, X86.EXCEPTION.GP_FAULT, sel, true);
|
||||
base = addrDesc = X86.ADDR_INVALID;
|
||||
break;
|
||||
}
|
||||
|
|
@ -772,7 +800,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
|
|||
this.addrIOPMLimit = (base + this.limit)|0;
|
||||
}
|
||||
}
|
||||
else if (this.id == X86Seg.ID.OTHER) {
|
||||
else if (this.id == X86Seg.ID.VER) {
|
||||
/*
|
||||
* For LSL, we must support any descriptor marked X86.DESC.ACC.TYPE.SEG, as well as TSS and LDT descriptors.
|
||||
*/
|
||||
|
|
@ -781,6 +809,9 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
|
|||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* The only other case should be X86Seg.ID.DBG, for which we do nothing.
|
||||
*/
|
||||
|
||||
this.sel = sel;
|
||||
this.base = base;
|
||||
|
|
@ -793,7 +824,9 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
|
|||
this.updateMode(true, true, false);
|
||||
break;
|
||||
}
|
||||
if (!fSuppress) this.messageSeg(sel, base, limit, type, ext);
|
||||
|
||||
if (DEBUG) this.messageSeg(sel, base, limit, type, ext);
|
||||
|
||||
return base;
|
||||
};
|
||||
|
||||
|
|
@ -1218,7 +1251,7 @@ X86Seg.prototype.updateMode = function(fLoad, fProt, fV86)
|
|||
X86Seg.prototype.messageSeg = function(sel, base, limit, type, ext)
|
||||
{
|
||||
if (DEBUG) {
|
||||
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(Messages.SEG)) {
|
||||
if (DEBUGGER && this.id != X86Seg.ID.DBG && 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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue