Fixed physical memory breakpoints when paging enabled
This commit is contained in:
parent
e1d06fb2d1
commit
e20cb1d0e3
28 changed files with 8248 additions and 1237 deletions
|
|
@ -84,6 +84,37 @@ if (DEBUGGER) {
|
|||
*/
|
||||
var DbgAddr;
|
||||
|
||||
/*
|
||||
* Debugger Breakpoint Tips
|
||||
*
|
||||
* Here's an example of our powerful new breakpoint command capabilities:
|
||||
*
|
||||
* bp 0397:022B "?'GlobalAlloc(wFlags:[ss:sp+8],dwBytes:[ss:sp+6][ss:sp+4])';g [ss:sp+2]:[ss:sp] '?ax;if ax'"
|
||||
*
|
||||
* The above breakpoint will display a pleasing "GlobalAlloc()" string containing the current
|
||||
* stack parameters, and will briefly stop execution on the return to print the result in AX,
|
||||
* halting the CPU whenever AX is zero (the default behavior of "if" whenever the expression is
|
||||
* false is to look for an "else" and automatically halt when there is no "else").
|
||||
*
|
||||
* 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
|
||||
* for you; eg:
|
||||
*
|
||||
* ## di 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
|
||||
* got easier, now that the PCjs Debugger mimics portions of the Windows Debugger INT 0x41 interface;
|
||||
* see intWindowsDebugger() for details. So even if you neglect to run WDEB386.EXE /E inside the
|
||||
* machine before running Windows, you should still see notifications like:
|
||||
*
|
||||
* KERNEL!undefined code(0001)=#0397 len 0000C580
|
||||
*
|
||||
* in the PCjs Debugger output window, as segments are being loaded by the Windows kernel.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Debugger(parmsDbg)
|
||||
*
|
||||
|
|
@ -2273,7 +2304,7 @@ if (DEBUGGER) {
|
|||
var b = 0xff;
|
||||
var addr = this.getAddr(dbgAddr, false, 1);
|
||||
if (addr !== X86.ADDR_INVALID) {
|
||||
b = this.cpu.probeAddr(addr, 1, dbgAddr.type != Debugger.ADDRTYPE.PHYSICAL) | 0;
|
||||
b = this.cpu.probeAddr(addr, 1, dbgAddr.type == Debugger.ADDRTYPE.PHYSICAL) | 0;
|
||||
if (inc) this.incAddr(dbgAddr, inc);
|
||||
}
|
||||
return b;
|
||||
|
|
@ -2305,7 +2336,7 @@ if (DEBUGGER) {
|
|||
var w = 0xffff;
|
||||
var addr = this.getAddr(dbgAddr, false, 2);
|
||||
if (addr !== X86.ADDR_INVALID) {
|
||||
w = this.cpu.probeAddr(addr, 2, dbgAddr.type != Debugger.ADDRTYPE.PHYSICAL);
|
||||
w = this.cpu.probeAddr(addr, 2, dbgAddr.type == Debugger.ADDRTYPE.PHYSICAL);
|
||||
if (inc) this.incAddr(dbgAddr, inc);
|
||||
}
|
||||
return w;
|
||||
|
|
@ -2324,7 +2355,7 @@ if (DEBUGGER) {
|
|||
var l = -1;
|
||||
var addr = this.getAddr(dbgAddr, false, 4);
|
||||
if (addr !== X86.ADDR_INVALID) {
|
||||
l = this.cpu.probeAddr(addr, 4, dbgAddr.type != Debugger.ADDRTYPE.PHYSICAL);
|
||||
l = this.cpu.probeAddr(addr, 4, dbgAddr.type == Debugger.ADDRTYPE.PHYSICAL);
|
||||
if (inc) this.incAddr(dbgAddr, inc);
|
||||
}
|
||||
return l;
|
||||
|
|
@ -4313,14 +4344,14 @@ if (DEBUGGER) {
|
|||
if (this.aBreakRead !== undefined) {
|
||||
for (i = 1; i < this.aBreakRead.length; i++) {
|
||||
dbgAddr = this.aBreakRead[i];
|
||||
this.cpu.removeMemBreak(this.getAddr(dbgAddr), false, dbgAddr.type != Debugger.ADDRTYPE.PHYSICAL);
|
||||
this.cpu.removeMemBreak(this.getAddr(dbgAddr), false, dbgAddr.type == Debugger.ADDRTYPE.PHYSICAL);
|
||||
}
|
||||
}
|
||||
this.aBreakRead = ["br"];
|
||||
if (this.aBreakWrite !== undefined) {
|
||||
for (i = 1; i < this.aBreakWrite.length; i++) {
|
||||
dbgAddr = this.aBreakWrite[i];
|
||||
this.cpu.removeMemBreak(this.getAddr(dbgAddr), true, dbgAddr.type != Debugger.ADDRTYPE.PHYSICAL);
|
||||
this.cpu.removeMemBreak(this.getAddr(dbgAddr), true, dbgAddr.type == Debugger.ADDRTYPE.PHYSICAL);
|
||||
}
|
||||
}
|
||||
this.aBreakWrite = ["bw"];
|
||||
|
|
@ -4353,33 +4384,6 @@ if (DEBUGGER) {
|
|||
* also consider a more WDEB386-like syntax, where "br" is used to set a variety of access-specific
|
||||
* breakpoints, using modifiers like "r1", "r2", "w1", "w2, etc.
|
||||
*
|
||||
* Here's an example of our powerful new breakpoint command capabilities:
|
||||
*
|
||||
* bp 0397:022B "?'GlobalAlloc(wFlags:[ss:sp+8],dwBytes:[ss:sp+6][ss:sp+4])';g [ss:sp+2]:[ss:sp] '?ax;if ax'"
|
||||
*
|
||||
* The above breakpoint will display a pleasing "GlobalAlloc()" string containing the current
|
||||
* stack parameters, and will briefly stop execution on the return to print the result in AX,
|
||||
* halting the CPU whenever AX is zero (the default behavior of "if" whenever the expression is
|
||||
* false is to look for an "else" and automatically halt when there is no "else").
|
||||
*
|
||||
* 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
|
||||
* for you; eg:
|
||||
*
|
||||
* ## di 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
|
||||
* got easier, now that the PCjs Debugger mimics portions of the Windows Debugger INT 0x41 interface;
|
||||
* see intWindowsDebugger() for details. So even if you neglect to run WDEB386.EXE /E inside the
|
||||
* machine before running Windows, you should still see notifications like:
|
||||
*
|
||||
* KERNEL!undefined code(0001)=#0397 len 0000C580
|
||||
*
|
||||
* in the PCjs Debugger output window, as segments are being loaded by the Windows kernel.
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {Array} aBreak
|
||||
* @param {DbgAddr} dbgAddr
|
||||
|
|
@ -4410,11 +4414,7 @@ if (DEBUGGER) {
|
|||
this.println("invalid address: " + this.toHexAddr(dbgAddr));
|
||||
fSuccess = false;
|
||||
} else {
|
||||
this.cpu.addMemBreak(addr, aBreak == this.aBreakWrite, dbgAddr.type != Debugger.ADDRTYPE.PHYSICAL);
|
||||
/*
|
||||
* Force memory breakpoints to use their linear address, by zapping the selector.
|
||||
*/
|
||||
dbgAddr.sel = null;
|
||||
this.cpu.addMemBreak(addr, aBreak == this.aBreakWrite, dbgAddr.type == Debugger.ADDRTYPE.PHYSICAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4469,7 +4469,7 @@ if (DEBUGGER) {
|
|||
}
|
||||
aBreak.splice(i, 1);
|
||||
if (aBreak != this.aBreakExec) {
|
||||
this.cpu.removeMemBreak(addr, aBreak == this.aBreakWrite, dbgAddrBreak.type != Debugger.ADDRTYPE.PHYSICAL);
|
||||
this.cpu.removeMemBreak(addr, aBreak == this.aBreakWrite, dbgAddrBreak.type == Debugger.ADDRTYPE.PHYSICAL);
|
||||
}
|
||||
/*
|
||||
* We'll mirror the logic in addBreakpoint() and leave the history buffer alone if this
|
||||
|
|
|
|||
|
|
@ -534,7 +534,7 @@ Memory.prototype = {
|
|||
* normal memory but also know how to update page tables. If any of the criteria are not met
|
||||
* for these special handlers, we fall back to the slower default "paged" memory handlers.
|
||||
*/
|
||||
if (TYPEDARRAYS && littleEndian && blockPhys.adw && !blockPhys.controller) {
|
||||
if (TYPEDARRAYS && littleEndian && blockPhys.adw && !blockPhys.controller && !blockPhys.cReadBreakpoints && !blockPhys.cWriteBreakpoints) {
|
||||
this.ab = blockPhys.ab;
|
||||
this.aw = blockPhys.aw;
|
||||
this.adw = blockPhys.adw;
|
||||
|
|
@ -855,8 +855,9 @@ Memory.prototype = {
|
|||
/**
|
||||
* readByteChecked(off, addr)
|
||||
*
|
||||
* TODO: Considering adding an assert that "this.addr + off === addr", and consider using that fact to eliminate
|
||||
* the extra 'addr' parameter.
|
||||
* NOTE: When we're called in the context of a PAGED block (eg, with one or more DEBUGGER breakpoints set),
|
||||
* the checkMemory functions need "this.addr + off" rather than "addr", because the former will be the physical
|
||||
* address rather than the linear address.
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {number} off
|
||||
|
|
@ -864,7 +865,7 @@ Memory.prototype = {
|
|||
* @return {number}
|
||||
*/
|
||||
readByteChecked: function readByteChecked(off, addr) {
|
||||
if (!DEBUGGER || !this.dbg || !this.dbg.checkMemoryRead(addr)) {
|
||||
if (!DEBUGGER || !this.dbg || this.addr == null || !this.dbg.checkMemoryRead(this.addr + off)) {
|
||||
if (I386 && this.cpu) this.cpu.checkMemoryException(addr, 1, false);
|
||||
}
|
||||
return this.readByteDirect(off, addr);
|
||||
|
|
@ -872,16 +873,13 @@ Memory.prototype = {
|
|||
/**
|
||||
* readShortChecked(off, addr)
|
||||
*
|
||||
* TODO: Considering adding an assert that "this.addr + off === addr", and consider using that fact to eliminate
|
||||
* the extra 'addr' parameter.
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {number} off
|
||||
* @param {number} addr
|
||||
* @return {number}
|
||||
*/
|
||||
readShortChecked: function readShortChecked(off, addr) {
|
||||
if (!DEBUGGER || !this.dbg || !this.dbg.checkMemoryRead(addr, 2)) {
|
||||
if (!DEBUGGER || !this.dbg || this.addr == null || !this.dbg.checkMemoryRead(this.addr + off, 2)) {
|
||||
if (I386 && this.cpu) this.cpu.checkMemoryException(addr, 2, false);
|
||||
}
|
||||
return this.readShortDirect(off, addr);
|
||||
|
|
@ -889,16 +887,13 @@ Memory.prototype = {
|
|||
/**
|
||||
* readLongChecked(off, addr)
|
||||
*
|
||||
* TODO: Considering adding an assert that "this.addr + off === addr", and consider using that fact to eliminate
|
||||
* the extra 'addr' parameter.
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {number} off
|
||||
* @param {number} addr
|
||||
* @return {number}
|
||||
*/
|
||||
readLongChecked: function readLongChecked(off, addr) {
|
||||
if (!DEBUGGER || !this.dbg || !this.dbg.checkMemoryRead(addr, 4)) {
|
||||
if (!DEBUGGER || !this.dbg || this.addr == null || !this.dbg.checkMemoryRead(this.addr + off, 4)) {
|
||||
if (I386 && this.cpu) this.cpu.checkMemoryException(addr, 4, false);
|
||||
}
|
||||
return this.readLongDirect(off, addr);
|
||||
|
|
@ -906,16 +901,13 @@ Memory.prototype = {
|
|||
/**
|
||||
* writeByteChecked(off, b, addr)
|
||||
*
|
||||
* TODO: Considering adding an assert that "this.addr + off === addr", and consider using that fact to eliminate
|
||||
* the extra 'addr' parameter.
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {number} off
|
||||
* @param {number} addr
|
||||
* @param {number} b
|
||||
*/
|
||||
writeByteChecked: function writeByteChecked(off, b, addr) {
|
||||
if (!DEBUGGER || !this.dbg || !this.dbg.checkMemoryWrite(addr)) {
|
||||
if (!DEBUGGER || !this.dbg || this.addr == null || !this.dbg.checkMemoryWrite(this.addr + off)) {
|
||||
if (I386 && this.cpu) this.cpu.checkMemoryException(addr, 1, true);
|
||||
}
|
||||
if (this.fReadOnly) this.writeNone(off, b, addr); else this.writeByteDirect(off, b, addr);
|
||||
|
|
@ -923,16 +915,13 @@ Memory.prototype = {
|
|||
/**
|
||||
* writeShortChecked(off, w, addr)
|
||||
*
|
||||
* TODO: Considering adding an assert that "this.addr + off === addr", and consider using that fact to eliminate
|
||||
* the extra 'addr' parameter.
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {number} off
|
||||
* @param {number} addr
|
||||
* @param {number} w
|
||||
*/
|
||||
writeShortChecked: function writeShortChecked(off, w, addr) {
|
||||
if (!DEBUGGER || !this.dbg || !this.dbg.checkMemoryWrite(addr, 2)) {
|
||||
if (!DEBUGGER || !this.dbg || this.addr == null || !this.dbg.checkMemoryWrite(this.addr + off, 2)) {
|
||||
if (I386 && this.cpu) this.cpu.checkMemoryException(addr, 2, true);
|
||||
}
|
||||
if (this.fReadOnly) this.writeNone(off, w, addr); else this.writeShortDirect(off, w, addr);
|
||||
|
|
@ -940,16 +929,13 @@ Memory.prototype = {
|
|||
/**
|
||||
* writeLongChecked(off, l, addr)
|
||||
*
|
||||
* TODO: Considering adding an assert that "this.addr + off === addr", and consider using that fact to eliminate
|
||||
* the extra 'addr' parameter.
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {number} off
|
||||
* @param {number} l
|
||||
* @param {number} addr
|
||||
*/
|
||||
writeLongChecked: function writeLongChecked(off, l, addr) {
|
||||
if (!DEBUGGER || !this.dbg || !this.dbg.checkMemoryWrite(addr, 4)) {
|
||||
if (!DEBUGGER || !this.dbg || this.addr == null || !this.dbg.checkMemoryWrite(this.addr + off, 4)) {
|
||||
if (I386 && this.cpu) this.cpu.checkMemoryException(addr, 4, true);
|
||||
}
|
||||
if (this.fReadOnly) this.writeNone(off, l, addr); else this.writeLongDirect(off, l, addr);
|
||||
|
|
|
|||
|
|
@ -298,7 +298,7 @@ X86CPU.prototype.setAddressMask = function(nBusMask)
|
|||
};
|
||||
|
||||
/**
|
||||
* addMemBreak(addr, fWrite, fLinear)
|
||||
* addMemBreak(addr, fWrite, fPhysical)
|
||||
*
|
||||
* NOTE: addMemBreak() could be merged with addMemCheck(), but the new merged interface would
|
||||
* have to provide one additional parameter indicating whether the Debugger or the CPU is the client.
|
||||
|
|
@ -308,19 +308,24 @@ X86CPU.prototype.setAddressMask = function(nBusMask)
|
|||
* @this {X86CPU}
|
||||
* @param {number} addr
|
||||
* @param {boolean} fWrite is true for a memory write breakpoint, false for a memory read breakpoint
|
||||
* @param {boolean} [fLinear] (true for linear breakpoint, false for physical)
|
||||
* @param {boolean} [fPhysical] (true for physical breakpoint, false for linear)
|
||||
*/
|
||||
X86CPU.prototype.addMemBreak = function(addr, fWrite, fLinear)
|
||||
X86CPU.prototype.addMemBreak = function(addr, fWrite, fPhysical)
|
||||
{
|
||||
if (DEBUGGER) {
|
||||
var iBlock = addr >>> this.nBlockShift;
|
||||
var aBlocks = (fLinear? this.aMemBlocks : this.aBusBlocks);
|
||||
var aBlocks = (fPhysical? this.aBusBlocks : this.aMemBlocks);
|
||||
aBlocks[iBlock].addBreakpoint(addr & this.nBlockLimit, fWrite);
|
||||
/*
|
||||
* When a physical memory breakpoint is added, a fresh setPhysBlock() call is REQUIRED for any
|
||||
* linear mappings to that address. This is a bit of a sledgehammer solution, but at least it's a solution.
|
||||
*/
|
||||
if (fPhysical) this.flushPageBlocks();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* removeMemBreak(addr, fWrite, fLinear)
|
||||
* removeMemBreak(addr, fWrite, fPhysical)
|
||||
*
|
||||
* NOTE: removeMemBreak() could be merged with removeMemCheck(), but the new merged interface would
|
||||
* have to provide one additional parameter indicating whether the Debugger or the CPU is the client.
|
||||
|
|
@ -330,14 +335,19 @@ X86CPU.prototype.addMemBreak = function(addr, fWrite, fLinear)
|
|||
* @this {X86CPU}
|
||||
* @param {number} addr
|
||||
* @param {boolean} fWrite is true for a memory write breakpoint, false for a memory read breakpoint
|
||||
* @param {boolean} [fLinear] (true for linear breakpoint, false for physical)
|
||||
* @param {boolean} [fPhysical] (true for physical breakpoint, false for linear)
|
||||
*/
|
||||
X86CPU.prototype.removeMemBreak = function(addr, fWrite, fLinear)
|
||||
X86CPU.prototype.removeMemBreak = function(addr, fWrite, fPhysical)
|
||||
{
|
||||
if (DEBUGGER) {
|
||||
var iBlock = addr >>> this.nBlockShift;
|
||||
var aBlocks = (fLinear? this.aMemBlocks : this.aBusBlocks);
|
||||
var aBlocks = (fPhysical? this.aBusBlocks : this.aMemBlocks);
|
||||
aBlocks[iBlock].removeBreakpoint(addr & this.nBlockLimit, fWrite);
|
||||
/*
|
||||
* When a physical memory breakpoint is removed, a fresh setPhysBlock() call is RECOMMENDED for any
|
||||
* linear mappings to that address. This is a bit of a sledgehammer solution, but at least it's a solution.
|
||||
*/
|
||||
if (fPhysical) this.flushPageBlocks();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -456,6 +466,17 @@ X86CPU.prototype.enablePageBlocks = function()
|
|||
this.aBlocksPaged = [];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* flushPageBlocks()
|
||||
*
|
||||
* @this {X86CPU}
|
||||
*/
|
||||
X86CPU.prototype.flushPageBlocks = function()
|
||||
{
|
||||
if (this.regCR0 & X86.CR0.PG) this.enablePageBlocks();
|
||||
}
|
||||
|
||||
/**
|
||||
* acquirePageBlock(addr)
|
||||
*
|
||||
|
|
@ -2988,7 +3009,7 @@ X86CPU.prototype.setBinding = function(sHTMLType, sBinding, control)
|
|||
};
|
||||
|
||||
/**
|
||||
* probeAddr(addr, size, fLinear)
|
||||
* probeAddr(addr, size, fPhysical)
|
||||
*
|
||||
* Used by the Debugger to probe addresses without risk of triggering a page fault, and by internal
|
||||
* functions, like fnCheckFault(), that must also avoid triggering faults, since they're not part of
|
||||
|
|
@ -3002,12 +3023,12 @@ X86CPU.prototype.setBinding = function(sHTMLType, sBinding, control)
|
|||
* @this {X86CPU}
|
||||
* @param {number} addr is a linear address
|
||||
* @param {number} [size] is a length (default is 1; if specified, must be 1, 2 or 4)
|
||||
* @param {boolean} [fLinear] (true for linear probe, false for physical; linear is the default)
|
||||
* @param {boolean} [fPhysical] (true for physical probe, false for linear; linear is the default)
|
||||
* @return {number|null} value at the specified address, or null if invalid
|
||||
*/
|
||||
X86CPU.prototype.probeAddr = function(addr, size, fLinear)
|
||||
X86CPU.prototype.probeAddr = function(addr, size, fPhysical)
|
||||
{
|
||||
var aBlocks = (fLinear === false? this.aBusBlocks : this.aMemBlocks);
|
||||
var aBlocks = (fPhysical? this.aBusBlocks : this.aMemBlocks);
|
||||
var block = aBlocks[(addr & this.nMemMask) >>> this.nBlockShift];
|
||||
if (block && block.type == Memory.TYPE.UNPAGED) block = this.mapPageBlock(addr, false, true);
|
||||
|
||||
|
|
@ -3020,16 +3041,16 @@ X86CPU.prototype.probeAddr = function(addr, size, fLinear)
|
|||
if (off < this.nBlockLimit) {
|
||||
return block.readShortDirect(off, addr);
|
||||
}
|
||||
return block.readByteDirect(off, addr) | (this.probeAddr(addr + 1, 1, fLinear) << 8);
|
||||
return block.readByteDirect(off, addr) | (this.probeAddr(addr + 1, 1, fPhysical) << 8);
|
||||
}
|
||||
if (size == 4) {
|
||||
if (off < this.nBlockLimit - 2) {
|
||||
return block.readLongDirect(off, addr);
|
||||
}
|
||||
if (off == this.nBlockLimit - 1) {
|
||||
return block.readShortDirect(off, addr) | (this.probeAddr(addr + 2, 2, fLinear) << 16);
|
||||
return block.readShortDirect(off, addr) | (this.probeAddr(addr + 2, 2, fPhysical) << 16);
|
||||
}
|
||||
return block.readByteDirect(off, addr) | (this.probeAddr(addr + 1, 1, fLinear) << 8) | (this.probeAddr(addr + 2, 1, fLinear) << 16) | (this.probeAddr(addr + 3, 1, fLinear) << 24);
|
||||
return block.readByteDirect(off, addr) | (this.probeAddr(addr + 1, 1, fPhysical) << 8) | (this.probeAddr(addr + 2, 1, fPhysical) << 16) | (this.probeAddr(addr + 3, 1, fPhysical) << 24);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1557,6 +1557,10 @@ X86.fnLCR0 = function(l)
|
|||
this.regCR0 = l;
|
||||
this.setProtMode();
|
||||
if (this.regCR0 & X86.CR0.PG) {
|
||||
/*
|
||||
* TODO: Determine if setting X86.CR0.PG when already set should really act as a flush;
|
||||
* I'm not currently worried about it, because I'm assuming CR0 is not rewritten that often.
|
||||
*/
|
||||
this.enablePageBlocks();
|
||||
} else {
|
||||
this.disablePageBlocks();
|
||||
|
|
@ -1579,7 +1583,7 @@ X86.fnLCR3 = function(l)
|
|||
* so let's ensure that the low 12 bits of regCR3 are always zero.
|
||||
*/
|
||||
this.assert(!(this.regCR3 & X86.LADDR.OFFSET));
|
||||
if (this.regCR0 & X86.CR0.PG) this.enablePageBlocks();
|
||||
this.flushPageBlocks();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in a new issue