More PAGEBLOCKS support
This commit is contained in:
parent
6108fb25ab
commit
453d84c6d8
7 changed files with 252 additions and 48 deletions
|
|
@ -39,6 +39,7 @@ if (typeof module !== 'undefined') {
|
|||
var Memory = require("./memory");
|
||||
var Messages = require("./messages");
|
||||
var State = require("./state");
|
||||
var X86 = require("./x86");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -67,8 +68,8 @@ if (typeof module !== 'undefined') {
|
|||
* @constructor
|
||||
* @extends Component
|
||||
* @param {Object} parmsBus
|
||||
* @param {X86CPU|Component} cpu
|
||||
* @param {Debugger|Component} dbg
|
||||
* @param {X86CPU} cpu
|
||||
* @param {Debugger} dbg
|
||||
*/
|
||||
function Bus(parmsBus, cpu, dbg)
|
||||
{
|
||||
|
|
@ -689,20 +690,59 @@ Bus.prototype.enablePageBlocks = function(addrPD)
|
|||
};
|
||||
|
||||
/**
|
||||
* mapPageBlock(addr)
|
||||
* mapPageBlock(addr, fWrite)
|
||||
*
|
||||
* If addr is a valid linear address, then we must obtain the following information:
|
||||
* Locate the corresponding physical PDE, PTE and memory blocks for the given linear address.
|
||||
*
|
||||
* (1) the physical Memory object corresponding to the linear address in addr
|
||||
* (2) the physical Memory object containing that memory's PTE
|
||||
* (3) the offset within the preceding physical Memory object of that memory's PTE
|
||||
*
|
||||
* Item (1) allows us to convert an "unpaged" Memory block in to a "paged" Memory block, and the combination of
|
||||
* (2) and (3) allows us to efficiently update the PTE whenever the page is accesssed and/or modified.
|
||||
* @this {Bus}
|
||||
* @param {number} addr is a linear address
|
||||
* @param {boolean} fWrite (true if called for a write, false if for a read)
|
||||
* @return {Memory|null}
|
||||
*/
|
||||
Bus.prototype.mapPageBlock = function(addr)
|
||||
Bus.prototype.mapPageBlock = function(addr, fWrite)
|
||||
{
|
||||
return null;
|
||||
var offPDE = (addr & X86.LADDR.PDE.MASK) >>> X86.LADDR.PDE.SHIFT;
|
||||
var addrPDE = this.cpu.regCR3 + offPDE; // TODO: adding offPDE could be eliminated, along with the busMask mask
|
||||
var blockPDE = this.aPhysBlocks[(addrPDE & this.busMask) >>> this.blockShift];
|
||||
var pde = blockPDE.readLong(offPDE);
|
||||
|
||||
if (!(pde & X86.PTE.PRESENT)) {
|
||||
X86.fnPageFault.call(this.cpu, addr, false, fWrite);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!(pde & X86.PTE.USER) && this.cpu.segCS.cpl == 3) {
|
||||
X86.fnPageFault.call(this.cpu, addr, true, fWrite);
|
||||
return null;
|
||||
}
|
||||
|
||||
var offPTE = (addr & X86.LADDR.PTE.MASK) >>> X86.LADDR.PTE.SHIFT;
|
||||
var addrPTE = (pde & X86.PTE.FRAME) + offPTE; // TODO: adding offPTE could be eliminated, along with the busMask mask
|
||||
var blockPTE = this.aPhysBlocks[(addrPTE & this.busMask) >>> this.blockShift];
|
||||
var pte = blockPTE.readLong(offPTE);
|
||||
|
||||
if (!(pte & X86.PTE.PRESENT)) {
|
||||
X86.fnPageFault.call(this.cpu, addr, false, fWrite);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!(pte & X86.PTE.USER) && this.cpu.segCS.cpl == 3) {
|
||||
X86.fnPageFault.call(this.cpu, addr, true, fWrite);
|
||||
return null;
|
||||
}
|
||||
|
||||
var addrPhys = (pte & X86.PTE.FRAME) + (addr & X86.LADDR.OFFSET); // TODO: Adding OFFSET could be eliminated, along with the busMask mask
|
||||
var blockPhys = this.aPhysBlocks[(addrPhys & this.busMask) >>> this.blockShift];
|
||||
|
||||
/*
|
||||
* So we have the block containing the physical memory corresponding to the given linear address.
|
||||
*
|
||||
* Now we create a new "paged" Memory block and record the physical block info using setPhysBlock().
|
||||
*/
|
||||
var addrPage = addr & ~X86.LADDR.OFFSET;
|
||||
var blockPage = new Memory(addrPage, 0, this.blockSize, Memory.TYPE.PAGED);
|
||||
blockPage.setPhysBlock(blockPage, blockPDE, offPDE, blockPTE, offPTE);
|
||||
return blockPage;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -140,13 +140,17 @@ function Computer(parmsComputer, parmsMachine, fSuspended) {
|
|||
|
||||
/*
|
||||
* Find the appropriate CPU (and Debugger and Control Panel, if any)
|
||||
*
|
||||
* CLOSURE COMPILER TIP: To override the type of a right-hand expression (as we need to do here,
|
||||
* where we know getComponentByType() will only return an X86CPU object or null), wrap the expression
|
||||
* in parentheses. I never knew this until I stumbled across it in "Closure: The Definitive Guide".
|
||||
*/
|
||||
this.cpu = Component.getComponentByType("CPU", this.id);
|
||||
this.cpu = /** @type {X86CPU} */ (Component.getComponentByType("CPU", this.id));
|
||||
if (!this.cpu) {
|
||||
Component.error("Unable to find CPU component");
|
||||
return;
|
||||
}
|
||||
this.dbg = Component.getComponentByType("Debugger", this.id);
|
||||
this.dbg = /** @type {Debugger} */ (Component.getComponentByType("Debugger", this.id));
|
||||
|
||||
/*
|
||||
* Initialize the Bus component
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ if (typeof module !== 'undefined') {
|
|||
global.BUGS_8086 = BUGS_8086;
|
||||
global.I386 = I386;
|
||||
global.COMPAQ386 = COMPAQ386;
|
||||
global.PAGEBLOCKS = PAGEBLOCKS;
|
||||
/*
|
||||
* TODO: When we're "required" by Node, should we return anything via module.exports?
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ if (typeof module !== 'undefined') {
|
|||
var str = require("../../shared/lib/strlib");
|
||||
var Component = require("../../shared/lib/component");
|
||||
var Messages = require("./messages");
|
||||
var X86 = require("./x86");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -201,14 +202,15 @@ function Memory(addr, used, size, type, controller, bus)
|
|||
* empty (that is, their data arrays are uninitialized) and the memory type is NONE.
|
||||
*/
|
||||
Memory.TYPE = {
|
||||
NONE: 0,
|
||||
RAM: 1,
|
||||
ROM: 2,
|
||||
VIDEO: 3,
|
||||
CTRL: 4,
|
||||
UNPAGED:5,
|
||||
NAMES: ["NONE", "RAM", "ROM", "VIDEO", "H/W"],
|
||||
COLORS: ["black", "blue", "green", "cyan"]
|
||||
NONE: 0,
|
||||
RAM: 1,
|
||||
ROM: 2,
|
||||
VIDEO: 3,
|
||||
CTRL: 4,
|
||||
UNPAGED: 5,
|
||||
PAGED: 6,
|
||||
NAMES: ["NONE", "RAM", "ROM", "VIDEO", "H/W", "UNPAGED", "PAGED"],
|
||||
COLORS: ["black", "blue", "green", "cyan"]
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -232,8 +234,8 @@ Memory.prototype = {
|
|||
clone: function(mem, type) {
|
||||
/*
|
||||
* Original memory block IDs are even; cloned memory block IDs are odd;
|
||||
* the original ID of the current block is lost, but that's OK, since it was
|
||||
* presumably produced merely to become a clone.
|
||||
* the original ID of the current block is lost, but that's OK, since it was presumably
|
||||
* produced merely to become a clone.
|
||||
*/
|
||||
this.id = mem.id | 0x1;
|
||||
this.used = mem.used;
|
||||
|
|
@ -361,7 +363,17 @@ Memory.prototype = {
|
|||
* @param {boolean} [fDirect]
|
||||
*/
|
||||
setAccess: function(afn, fDirect) {
|
||||
afn = afn || (this.type == Memory.TYPE.UNPAGED? Memory.afnUnpaged : Memory.afnNone);
|
||||
if (!afn) {
|
||||
if (this.type == Memory.TYPE.UNPAGED) {
|
||||
afn = Memory.afnUnpaged;
|
||||
}
|
||||
else if (this.type == Memory.TYPE.PAGED) {
|
||||
afn = Memory.afnPaged;
|
||||
} else {
|
||||
Component.assert(this.type == Memory.TYPE.NONE);
|
||||
afn = Memory.afnNone;
|
||||
}
|
||||
}
|
||||
if (fDirect === undefined) fDirect = true; // TODO: Verify that this is desired default behavior
|
||||
this.setReadAccess(afn, fDirect);
|
||||
this.setWriteAccess(afn, fDirect);
|
||||
|
|
@ -424,7 +436,7 @@ Memory.prototype = {
|
|||
* setDebugger(dbg, addr, size)
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {Debugger|Component} dbg
|
||||
* @param {Debugger} dbg
|
||||
* @param {number} addr of block
|
||||
* @param {number} size of block
|
||||
*/
|
||||
|
|
@ -437,14 +449,48 @@ Memory.prototype = {
|
|||
}
|
||||
},
|
||||
/**
|
||||
* setPageBlock(addr)
|
||||
* adjustEndian(dw)
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {number} dw
|
||||
* @return {number}
|
||||
*/
|
||||
adjustEndian: function(dw) {
|
||||
if (TYPEDARRAYS && !littleEndian) {
|
||||
dw = (dw << 24) | ((dw << 8) & 0x00ff0000) | ((dw >> 8) & 0x0000ff00) | (dw >>> 24);
|
||||
}
|
||||
return dw;
|
||||
},
|
||||
/**
|
||||
* getPageBlock(addr, fWrite)
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {number} addr
|
||||
* @param {boolean} fWrite (true if called for a write, false if for a read)
|
||||
* @return {Memory}
|
||||
*/
|
||||
setPageBlock: function(addr) {
|
||||
return this.bus.mapPageBlock(addr);
|
||||
getPageBlock: function(addr, fWrite) {
|
||||
var block = this.bus.mapPageBlock(addr, fWrite);
|
||||
return block || this;
|
||||
},
|
||||
/**
|
||||
* setPhysBlock(blockPhys, blockPDE, offPDE, blockPTE, offPTE)
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {Memory} blockPhys
|
||||
* @param {Memory} blockPDE
|
||||
* @param {number} offPDE
|
||||
* @param {Memory} blockPTE
|
||||
* @param {number} offPTE
|
||||
*/
|
||||
setPhysBlock: function(blockPhys, blockPDE, offPDE, blockPTE, offPTE) {
|
||||
this.blockPhys = blockPhys;
|
||||
this.blockPDE = blockPDE;
|
||||
this.iPDE = offPDE >> 2; // convert offPDE into an adw index (iPDE)
|
||||
this.blockPTE = blockPTE;
|
||||
this.iPTE = offPTE >> 2; // convert offPTE into an adw index (iPTE)
|
||||
this.bitPTEDirty = this.adjustEndian(X86.PTE.ACCESSED | X86.PTE.DIRTY);
|
||||
this.bitPTEAccessed = this.adjustEndian(X86.PTE.ACCESSED);
|
||||
},
|
||||
/**
|
||||
* addBreakpoint(off, fWrite)
|
||||
|
|
@ -679,11 +725,6 @@ Memory.prototype = {
|
|||
var idw = off >> 2;
|
||||
var nShift = (off & 0x3) << 3;
|
||||
if (nShift < 24) {
|
||||
/*
|
||||
* 0: 0xffff0000
|
||||
* 8: 0xff0000ff
|
||||
* 16: 0x0000ffff
|
||||
*/
|
||||
this.adw[idw] = (this.adw[idw] & ~(0xffff << nShift)) | (w << nShift);
|
||||
} else {
|
||||
this.adw[idw] = (this.adw[idw] & 0x00ffffff) | (w << 24);
|
||||
|
|
@ -714,11 +755,6 @@ Memory.prototype = {
|
|||
if (!nShift) {
|
||||
this.adw[idw] = l;
|
||||
} else {
|
||||
/*
|
||||
* 8: 0xffffff00
|
||||
* 16: 0xffff0000
|
||||
* 24: 0xff000000
|
||||
*/
|
||||
var mask = (0xffffffff|0) << nShift;
|
||||
this.adw[idw] = (this.adw[idw] & ~mask) | (l << nShift);
|
||||
idw++;
|
||||
|
|
@ -815,6 +851,84 @@ Memory.prototype = {
|
|||
}
|
||||
this.writeLongDirect(off, l);
|
||||
},
|
||||
/**
|
||||
* readBytePaged(off, addr)
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {number} off
|
||||
* @param {number} addr
|
||||
* @return {number}
|
||||
*/
|
||||
readBytePaged: function readBytePaged(off, addr) {
|
||||
this.blockPDE.adw[this.iPDE] |= this.bitPTEAccessed;
|
||||
this.blockPTE.adw[this.iPTE] |= this.bitPTEAccessed;
|
||||
return this.blockPhys.readByte(off, addr);
|
||||
},
|
||||
/**
|
||||
* readShortPaged(off, addr)
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {number} off
|
||||
* @param {number} addr
|
||||
* @return {number}
|
||||
*/
|
||||
readShortPaged: function readShortPaged(off, addr) {
|
||||
this.blockPDE.adw[this.iPDE] |= this.bitPTEAccessed;
|
||||
this.blockPTE.adw[this.iPTE] |= this.bitPTEAccessed;
|
||||
return this.blockPhys.readShort(off, addr);
|
||||
},
|
||||
/**
|
||||
* readLongPaged(off, addr)
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {number} off
|
||||
* @param {number} addr
|
||||
* @return {number}
|
||||
*/
|
||||
readLongPaged: function readLongPaged(off, addr) {
|
||||
this.blockPDE.adw[this.iPDE] |= this.bitPTEAccessed;
|
||||
this.blockPTE.adw[this.iPTE] |= this.bitPTEAccessed;
|
||||
return this.blockPhys.readLong(off, addr);
|
||||
},
|
||||
/**
|
||||
* writeBytePaged(off, b, addr)
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {number} off
|
||||
* @param {number} b
|
||||
* @param {number} addr
|
||||
*/
|
||||
writeBytePaged: function writeBytePaged(off, b, addr) {
|
||||
this.blockPDE.adw[this.iPDE] |= this.bitPTEAccessed;
|
||||
this.blockPTE.adw[this.iPTE] |= this.bitPTEDirty;
|
||||
this.blockPhys.writeByte(off, b, addr);
|
||||
},
|
||||
/**
|
||||
* writeShortPaged(off, w, addr)
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {number} off
|
||||
* @param {number} w
|
||||
* @param {number} addr
|
||||
*/
|
||||
writeShortPaged: function writeShortPaged(off, w, addr) {
|
||||
this.blockPDE.adw[this.iPDE] |= this.bitPTEAccessed;
|
||||
this.blockPTE.adw[this.iPTE] |= this.bitPTEDirty;
|
||||
this.blockPhys.writeShort(off, w, addr);
|
||||
},
|
||||
/**
|
||||
* writeLongPaged(off, l, addr)
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {number} off
|
||||
* @param {number} l
|
||||
* @param {number} addr
|
||||
*/
|
||||
writeLongPaged: function writeLongPaged(off, l, addr) {
|
||||
this.blockPDE.adw[this.iPDE] |= this.bitPTEAccessed;
|
||||
this.blockPTE.adw[this.iPTE] |= this.bitPTEDirty;
|
||||
this.blockPhys.writeLong(off, l, addr);
|
||||
},
|
||||
/**
|
||||
* readByteUnpaged(off, addr)
|
||||
*
|
||||
|
|
@ -824,7 +938,7 @@ Memory.prototype = {
|
|||
* @return {number}
|
||||
*/
|
||||
readByteUnpaged: function readByteUnpaged(off, addr) {
|
||||
return this.setPageBlock(addr).readByte(off, addr);
|
||||
return this.getPageBlock(addr, false).readByte(off, addr);
|
||||
},
|
||||
/**
|
||||
* readShortUnpaged(off, addr)
|
||||
|
|
@ -835,7 +949,7 @@ Memory.prototype = {
|
|||
* @return {number}
|
||||
*/
|
||||
readShortUnpaged: function readShortUnpaged(off, addr) {
|
||||
return this.setPageBlock(addr).readShort(off, addr);
|
||||
return this.getPageBlock(addr, false).readShort(off, addr);
|
||||
},
|
||||
/**
|
||||
* readLongUnpaged(off, addr)
|
||||
|
|
@ -846,7 +960,7 @@ Memory.prototype = {
|
|||
* @return {number}
|
||||
*/
|
||||
readLongUnpaged: function readLongUnpaged(off, addr) {
|
||||
return this.setPageBlock(addr).readLong(off, addr);
|
||||
return this.getPageBlock(addr, false).readLong(off, addr);
|
||||
},
|
||||
/**
|
||||
* writeByteUnpaged(off, b, addr)
|
||||
|
|
@ -857,7 +971,7 @@ Memory.prototype = {
|
|||
* @param {number} addr
|
||||
*/
|
||||
writeByteUnpaged: function writeByteUnpaged(off, b, addr) {
|
||||
this.setPageBlock(addr).writeByte(off, b, addr);
|
||||
this.getPageBlock(addr, true).writeByte(off, b, addr);
|
||||
},
|
||||
/**
|
||||
* writeShortUnpaged(off, w, addr)
|
||||
|
|
@ -868,7 +982,7 @@ Memory.prototype = {
|
|||
* @param {number} addr
|
||||
*/
|
||||
writeShortUnpaged: function writeShortUnpaged(off, w, addr) {
|
||||
this.setPageBlock(addr).writeShort(off, w, addr);
|
||||
this.getPageBlock(addr, true).writeShort(off, w, addr);
|
||||
},
|
||||
/**
|
||||
* writeLongUnpaged(off, l, addr)
|
||||
|
|
@ -879,7 +993,7 @@ Memory.prototype = {
|
|||
* @param {number} addr
|
||||
*/
|
||||
writeLongUnpaged: function writeLongUnpaged(off, l, addr) {
|
||||
this.setPageBlock(addr).writeLong(off, l, addr);
|
||||
this.getPageBlock(addr, true).writeLong(off, l, addr);
|
||||
},
|
||||
/**
|
||||
* readByteBigEndian(off, addr)
|
||||
|
|
@ -1132,8 +1246,8 @@ Memory.prototype = {
|
|||
};
|
||||
|
||||
/*
|
||||
* This is the effective definition of afnNone, but we need not fully define it, because setAccess() already
|
||||
* uses these defaults when any of the 6 handlers (ie, 3 read handlers followed by 3 write handlers) are undefined.
|
||||
* This is the effective definition of afnNone, but we need not fully define it, because setAccess()
|
||||
* uses these defaults when any of the 6 handlers (ie, 3 read handlers and 3 write handlers) are undefined.
|
||||
*
|
||||
Memory.afnNone = [Memory.prototype.readNone, Memory.prototype.readShortDefault, Memory.prototype.readLongDefault, Memory.prototype.writeNone, Memory.prototype.writeShortDefault, Memory.prototype.writeLongDefault];
|
||||
*/
|
||||
|
|
@ -1143,7 +1257,7 @@ Memory.afnMemory = [Memory.prototype.readByteMemory, Memory.prototyp
|
|||
Memory.afnChecked = [Memory.prototype.readByteChecked, Memory.prototype.readShortChecked, Memory.prototype.readLongChecked, Memory.prototype.writeByteChecked, Memory.prototype.writeShortChecked, Memory.prototype.writeLongChecked];
|
||||
|
||||
if (PAGEBLOCKS) {
|
||||
// Memory.afnPaged = [Memory.prototype.readBytePaged, Memory.prototype.readShortPaged, Memory.prototype.readLongPaged, Memory.prototype.writeBytePaged, Memory.prototype.writeShortPaged, Memory.prototype.writeLongPaged];
|
||||
Memory.afnPaged = [Memory.prototype.readBytePaged, Memory.prototype.readShortPaged, Memory.prototype.readLongPaged, Memory.prototype.writeBytePaged, Memory.prototype.writeShortPaged, Memory.prototype.writeLongPaged];
|
||||
Memory.afnUnpaged = [Memory.prototype.readByteUnpaged, Memory.prototype.readShortUnpaged, Memory.prototype.readLongUnpaged, Memory.prototype.writeByteUnpaged, Memory.prototype.writeShortUnpaged, Memory.prototype.writeLongUnpaged];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -171,6 +171,25 @@ var X86 = {
|
|||
},
|
||||
INVALID: 0 // use X86.DESC.INVALID for invalid DESC values
|
||||
},
|
||||
LADDR: { // linear address
|
||||
PDE: { // index of page directory entry
|
||||
MASK: 0xffc00000,
|
||||
SHIFT: 20 // (addr & DIR.MASK) >>> DIR.SHIFT yields a page directory offset (ie, index * 4)
|
||||
},
|
||||
PTE: { // index of page table entry
|
||||
MASK: 0x003ff000,
|
||||
SHIFT: 10 // (addr & PAGE.MASK) >>> PAGE.SHIFT yields a page table offset (ie, index * 4)
|
||||
},
|
||||
OFFSET: 0x00000fff
|
||||
},
|
||||
PTE: {
|
||||
FRAME: 0xfffff000,
|
||||
DIRTY: 0x00000040, // page has been modified
|
||||
ACCESSED: 0x00000020, // page has been accessed
|
||||
USER: 0x00000004, // set for user level (CPL 3), clear for supervisor level (CPL 0-2)
|
||||
READWRITE: 0x00000002, // set for read/write, clear for read-only (affects CPL 3 only)
|
||||
PRESENT: 0x00000001 // set for present page, clear for not-present page
|
||||
},
|
||||
TSS: {
|
||||
PREV_TSS: 0x00,
|
||||
CPL0_SP: 0x02, // start of values altered by task switches
|
||||
|
|
@ -234,6 +253,7 @@ var X86 = {
|
|||
NP_FAULT: 0x0B, // Not Present Fault (protected-mode only)
|
||||
SS_FAULT: 0x0C, // Stack Fault (protected-mode only)
|
||||
GP_FAULT: 0x0D, // General Protection Fault
|
||||
PG_FAULT: 0x0E, // Page Fault
|
||||
MF_FAULT: 0x10 // Math Fault (see ESC or WAIT)
|
||||
},
|
||||
ERRCODE: {
|
||||
|
|
|
|||
|
|
@ -3461,6 +3461,26 @@ X86.fnFault = function(nFault, nError, fHalt)
|
|||
this.opFlags &= ~(X86.OPFLAG.NOREAD | X86.OPFLAG.NOWRITE);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnPageFault(addr, fPresent, fWrite)
|
||||
*
|
||||
* Helper to dispatch page faults.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} addr
|
||||
* @param {boolean} fPresent
|
||||
* @param {boolean} fWrite
|
||||
*/
|
||||
X86.fnPageFault = function(addr, fPresent, fWrite)
|
||||
{
|
||||
this.regCR2 = addr;
|
||||
var nError = 0;
|
||||
if (fPresent) nError |= X86.PTE.PRESENT;
|
||||
if (fWrite) nError |= X86.PTE.READWRITE;
|
||||
if (this.segCS.cpl == 3) nError |= X86.PTE.USER;
|
||||
X86.fnFault.call(this, X86.EXCEPTION.PG_FAULT, nError);
|
||||
};
|
||||
|
||||
/**
|
||||
* fnFaultMessage()
|
||||
*
|
||||
|
|
|
|||
|
|
@ -307,6 +307,11 @@ X86.opMOVcr = function MOVcr()
|
|||
break;
|
||||
case 0x3:
|
||||
this.regCR3 = this.regEBX;
|
||||
/*
|
||||
* Normal use of regCR3 involves adding a 0-4K (12-bit) offset to obtain a page directory entry, so
|
||||
* let's ensure that the low 12 bits of regCR3 are always zero.
|
||||
*/
|
||||
this.assert(!(this.regCR3 & X86.LADDR.OFFSET));
|
||||
this.regEBX = temp;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue