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 Memory = require("./memory");
|
||||||
var Messages = require("./messages");
|
var Messages = require("./messages");
|
||||||
var State = require("./state");
|
var State = require("./state");
|
||||||
|
var X86 = require("./x86");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -67,8 +68,8 @@ if (typeof module !== 'undefined') {
|
||||||
* @constructor
|
* @constructor
|
||||||
* @extends Component
|
* @extends Component
|
||||||
* @param {Object} parmsBus
|
* @param {Object} parmsBus
|
||||||
* @param {X86CPU|Component} cpu
|
* @param {X86CPU} cpu
|
||||||
* @param {Debugger|Component} dbg
|
* @param {Debugger} dbg
|
||||||
*/
|
*/
|
||||||
function Bus(parmsBus, cpu, 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
|
* @this {Bus}
|
||||||
* (2) the physical Memory object containing that memory's PTE
|
* @param {number} addr is a linear address
|
||||||
* (3) the offset within the preceding physical Memory object of that memory's PTE
|
* @param {boolean} fWrite (true if called for a write, false if for a read)
|
||||||
*
|
* @return {Memory|null}
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
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)
|
* 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) {
|
if (!this.cpu) {
|
||||||
Component.error("Unable to find CPU component");
|
Component.error("Unable to find CPU component");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.dbg = Component.getComponentByType("Debugger", this.id);
|
this.dbg = /** @type {Debugger} */ (Component.getComponentByType("Debugger", this.id));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize the Bus component
|
* Initialize the Bus component
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,7 @@ if (typeof module !== 'undefined') {
|
||||||
global.BUGS_8086 = BUGS_8086;
|
global.BUGS_8086 = BUGS_8086;
|
||||||
global.I386 = I386;
|
global.I386 = I386;
|
||||||
global.COMPAQ386 = COMPAQ386;
|
global.COMPAQ386 = COMPAQ386;
|
||||||
|
global.PAGEBLOCKS = PAGEBLOCKS;
|
||||||
/*
|
/*
|
||||||
* TODO: When we're "required" by Node, should we return anything via module.exports?
|
* 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 str = require("../../shared/lib/strlib");
|
||||||
var Component = require("../../shared/lib/component");
|
var Component = require("../../shared/lib/component");
|
||||||
var Messages = require("./messages");
|
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.
|
* empty (that is, their data arrays are uninitialized) and the memory type is NONE.
|
||||||
*/
|
*/
|
||||||
Memory.TYPE = {
|
Memory.TYPE = {
|
||||||
NONE: 0,
|
NONE: 0,
|
||||||
RAM: 1,
|
RAM: 1,
|
||||||
ROM: 2,
|
ROM: 2,
|
||||||
VIDEO: 3,
|
VIDEO: 3,
|
||||||
CTRL: 4,
|
CTRL: 4,
|
||||||
UNPAGED:5,
|
UNPAGED: 5,
|
||||||
NAMES: ["NONE", "RAM", "ROM", "VIDEO", "H/W"],
|
PAGED: 6,
|
||||||
COLORS: ["black", "blue", "green", "cyan"]
|
NAMES: ["NONE", "RAM", "ROM", "VIDEO", "H/W", "UNPAGED", "PAGED"],
|
||||||
|
COLORS: ["black", "blue", "green", "cyan"]
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -232,8 +234,8 @@ Memory.prototype = {
|
||||||
clone: function(mem, type) {
|
clone: function(mem, type) {
|
||||||
/*
|
/*
|
||||||
* Original memory block IDs are even; cloned memory block IDs are odd;
|
* 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
|
* the original ID of the current block is lost, but that's OK, since it was presumably
|
||||||
* presumably produced merely to become a clone.
|
* produced merely to become a clone.
|
||||||
*/
|
*/
|
||||||
this.id = mem.id | 0x1;
|
this.id = mem.id | 0x1;
|
||||||
this.used = mem.used;
|
this.used = mem.used;
|
||||||
|
|
@ -361,7 +363,17 @@ Memory.prototype = {
|
||||||
* @param {boolean} [fDirect]
|
* @param {boolean} [fDirect]
|
||||||
*/
|
*/
|
||||||
setAccess: function(afn, 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
|
if (fDirect === undefined) fDirect = true; // TODO: Verify that this is desired default behavior
|
||||||
this.setReadAccess(afn, fDirect);
|
this.setReadAccess(afn, fDirect);
|
||||||
this.setWriteAccess(afn, fDirect);
|
this.setWriteAccess(afn, fDirect);
|
||||||
|
|
@ -424,7 +436,7 @@ Memory.prototype = {
|
||||||
* setDebugger(dbg, addr, size)
|
* setDebugger(dbg, addr, size)
|
||||||
*
|
*
|
||||||
* @this {Memory}
|
* @this {Memory}
|
||||||
* @param {Debugger|Component} dbg
|
* @param {Debugger} dbg
|
||||||
* @param {number} addr of block
|
* @param {number} addr of block
|
||||||
* @param {number} size 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}
|
* @this {Memory}
|
||||||
* @param {number} addr
|
* @param {number} addr
|
||||||
|
* @param {boolean} fWrite (true if called for a write, false if for a read)
|
||||||
* @return {Memory}
|
* @return {Memory}
|
||||||
*/
|
*/
|
||||||
setPageBlock: function(addr) {
|
getPageBlock: function(addr, fWrite) {
|
||||||
return this.bus.mapPageBlock(addr);
|
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)
|
* addBreakpoint(off, fWrite)
|
||||||
|
|
@ -679,11 +725,6 @@ Memory.prototype = {
|
||||||
var idw = off >> 2;
|
var idw = off >> 2;
|
||||||
var nShift = (off & 0x3) << 3;
|
var nShift = (off & 0x3) << 3;
|
||||||
if (nShift < 24) {
|
if (nShift < 24) {
|
||||||
/*
|
|
||||||
* 0: 0xffff0000
|
|
||||||
* 8: 0xff0000ff
|
|
||||||
* 16: 0x0000ffff
|
|
||||||
*/
|
|
||||||
this.adw[idw] = (this.adw[idw] & ~(0xffff << nShift)) | (w << nShift);
|
this.adw[idw] = (this.adw[idw] & ~(0xffff << nShift)) | (w << nShift);
|
||||||
} else {
|
} else {
|
||||||
this.adw[idw] = (this.adw[idw] & 0x00ffffff) | (w << 24);
|
this.adw[idw] = (this.adw[idw] & 0x00ffffff) | (w << 24);
|
||||||
|
|
@ -714,11 +755,6 @@ Memory.prototype = {
|
||||||
if (!nShift) {
|
if (!nShift) {
|
||||||
this.adw[idw] = l;
|
this.adw[idw] = l;
|
||||||
} else {
|
} else {
|
||||||
/*
|
|
||||||
* 8: 0xffffff00
|
|
||||||
* 16: 0xffff0000
|
|
||||||
* 24: 0xff000000
|
|
||||||
*/
|
|
||||||
var mask = (0xffffffff|0) << nShift;
|
var mask = (0xffffffff|0) << nShift;
|
||||||
this.adw[idw] = (this.adw[idw] & ~mask) | (l << nShift);
|
this.adw[idw] = (this.adw[idw] & ~mask) | (l << nShift);
|
||||||
idw++;
|
idw++;
|
||||||
|
|
@ -815,6 +851,84 @@ Memory.prototype = {
|
||||||
}
|
}
|
||||||
this.writeLongDirect(off, l);
|
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)
|
* readByteUnpaged(off, addr)
|
||||||
*
|
*
|
||||||
|
|
@ -824,7 +938,7 @@ Memory.prototype = {
|
||||||
* @return {number}
|
* @return {number}
|
||||||
*/
|
*/
|
||||||
readByteUnpaged: function readByteUnpaged(off, addr) {
|
readByteUnpaged: function readByteUnpaged(off, addr) {
|
||||||
return this.setPageBlock(addr).readByte(off, addr);
|
return this.getPageBlock(addr, false).readByte(off, addr);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* readShortUnpaged(off, addr)
|
* readShortUnpaged(off, addr)
|
||||||
|
|
@ -835,7 +949,7 @@ Memory.prototype = {
|
||||||
* @return {number}
|
* @return {number}
|
||||||
*/
|
*/
|
||||||
readShortUnpaged: function readShortUnpaged(off, addr) {
|
readShortUnpaged: function readShortUnpaged(off, addr) {
|
||||||
return this.setPageBlock(addr).readShort(off, addr);
|
return this.getPageBlock(addr, false).readShort(off, addr);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* readLongUnpaged(off, addr)
|
* readLongUnpaged(off, addr)
|
||||||
|
|
@ -846,7 +960,7 @@ Memory.prototype = {
|
||||||
* @return {number}
|
* @return {number}
|
||||||
*/
|
*/
|
||||||
readLongUnpaged: function readLongUnpaged(off, addr) {
|
readLongUnpaged: function readLongUnpaged(off, addr) {
|
||||||
return this.setPageBlock(addr).readLong(off, addr);
|
return this.getPageBlock(addr, false).readLong(off, addr);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* writeByteUnpaged(off, b, addr)
|
* writeByteUnpaged(off, b, addr)
|
||||||
|
|
@ -857,7 +971,7 @@ Memory.prototype = {
|
||||||
* @param {number} addr
|
* @param {number} addr
|
||||||
*/
|
*/
|
||||||
writeByteUnpaged: function writeByteUnpaged(off, b, 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)
|
* writeShortUnpaged(off, w, addr)
|
||||||
|
|
@ -868,7 +982,7 @@ Memory.prototype = {
|
||||||
* @param {number} addr
|
* @param {number} addr
|
||||||
*/
|
*/
|
||||||
writeShortUnpaged: function writeShortUnpaged(off, w, 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)
|
* writeLongUnpaged(off, l, addr)
|
||||||
|
|
@ -879,7 +993,7 @@ Memory.prototype = {
|
||||||
* @param {number} addr
|
* @param {number} addr
|
||||||
*/
|
*/
|
||||||
writeLongUnpaged: function writeLongUnpaged(off, l, 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)
|
* 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
|
* 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 followed by 3 write handlers) are undefined.
|
* 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];
|
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];
|
Memory.afnChecked = [Memory.prototype.readByteChecked, Memory.prototype.readShortChecked, Memory.prototype.readLongChecked, Memory.prototype.writeByteChecked, Memory.prototype.writeShortChecked, Memory.prototype.writeLongChecked];
|
||||||
|
|
||||||
if (PAGEBLOCKS) {
|
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];
|
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
|
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: {
|
TSS: {
|
||||||
PREV_TSS: 0x00,
|
PREV_TSS: 0x00,
|
||||||
CPL0_SP: 0x02, // start of values altered by task switches
|
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)
|
NP_FAULT: 0x0B, // Not Present Fault (protected-mode only)
|
||||||
SS_FAULT: 0x0C, // Stack Fault (protected-mode only)
|
SS_FAULT: 0x0C, // Stack Fault (protected-mode only)
|
||||||
GP_FAULT: 0x0D, // General Protection Fault
|
GP_FAULT: 0x0D, // General Protection Fault
|
||||||
|
PG_FAULT: 0x0E, // Page Fault
|
||||||
MF_FAULT: 0x10 // Math Fault (see ESC or WAIT)
|
MF_FAULT: 0x10 // Math Fault (see ESC or WAIT)
|
||||||
},
|
},
|
||||||
ERRCODE: {
|
ERRCODE: {
|
||||||
|
|
|
||||||
|
|
@ -3461,6 +3461,26 @@ X86.fnFault = function(nFault, nError, fHalt)
|
||||||
this.opFlags &= ~(X86.OPFLAG.NOREAD | X86.OPFLAG.NOWRITE);
|
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()
|
* fnFaultMessage()
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -307,6 +307,11 @@ X86.opMOVcr = function MOVcr()
|
||||||
break;
|
break;
|
||||||
case 0x3:
|
case 0x3:
|
||||||
this.regCR3 = this.regEBX;
|
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;
|
this.regEBX = temp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue