Fixed LGDT and LIDT, fixed read-only memory, and fixed mode transition tests
This commit is contained in:
parent
9ab1f92adc
commit
cfa4e0207f
5 changed files with 158 additions and 104 deletions
|
|
@ -593,7 +593,7 @@ Memory.prototype = {
|
|||
* @return {number}
|
||||
*/
|
||||
readShortDefault: function readShortDefault(off, addr) {
|
||||
return this.readByteDirect(off, addr) | (this.readByteDirect(off + 1, addr) << 8);
|
||||
return this.readByte(off, addr) | (this.readByte(off + 1, addr) << 8);
|
||||
},
|
||||
/**
|
||||
* readLongDefault(off, addr)
|
||||
|
|
@ -604,7 +604,7 @@ Memory.prototype = {
|
|||
* @return {number}
|
||||
*/
|
||||
readLongDefault: function readLongDefault(off, addr) {
|
||||
return this.readByteDirect(off, addr) | (this.readByteDirect(off + 1, addr) << 8) | (this.readByteDirect(off + 2, addr) << 16) | (this.readByteDirect(off + 3, addr) << 24);
|
||||
return this.readByte(off, addr) | (this.readByte(off + 1, addr) << 8) | (this.readByte(off + 2, addr) << 16) | (this.readByte(off + 3, addr) << 24);
|
||||
},
|
||||
/**
|
||||
* writeShortDefault(off, w, addr)
|
||||
|
|
@ -616,8 +616,8 @@ Memory.prototype = {
|
|||
*/
|
||||
writeShortDefault: function writeShortDefault(off, w, addr) {
|
||||
Component.assert(!(w & ~0xffff));
|
||||
this.writeByteDirect(off, w & 0xff);
|
||||
this.writeByteDirect(off + 1, w >> 8);
|
||||
this.writeByte(off, w & 0xff);
|
||||
this.writeByte(off + 1, w >> 8);
|
||||
},
|
||||
/**
|
||||
* writeLongDefault(off, w, addr)
|
||||
|
|
@ -628,10 +628,10 @@ Memory.prototype = {
|
|||
* @param {number} addr
|
||||
*/
|
||||
writeLongDefault: function writeLongDefault(off, w, addr) {
|
||||
this.writeByteDirect(off, w & 0xff);
|
||||
this.writeByteDirect(off + 1, (w >> 8) & 0xff);
|
||||
this.writeByteDirect(off + 2, (w >> 16) & 0xff);
|
||||
this.writeByteDirect(off + 3, (w >>> 24));
|
||||
this.writeByte(off, w & 0xff);
|
||||
this.writeByte(off + 1, (w >> 8) & 0xff);
|
||||
this.writeByte(off + 2, (w >> 16) & 0xff);
|
||||
this.writeByte(off + 3, (w >>> 24));
|
||||
},
|
||||
/**
|
||||
* readByteMemory(off, addr)
|
||||
|
|
|
|||
|
|
@ -1445,9 +1445,13 @@ X86.fnLFS = function LFS(dst, src)
|
|||
*
|
||||
* op=0x0F,0x01,reg=0x2 (GRP7:LGDT)
|
||||
*
|
||||
* The 80286 LGDT instruction expects a 40-bit operand: a 16-bit limit, followed by a 24-bit address
|
||||
* (or a 32-bit address in 32-bit mode); the ModRM decoder has already supplied the first word of the
|
||||
* operand (in dst), which corresponds to the limit, so we must fetch the remaining bits ourselves.
|
||||
* The 80286 LGDT instruction assumes a 40-bit operand: a 16-bit limit followed by a 24-bit base address;
|
||||
* the ModRM decoder has already supplied the first word of the operand (in dst), which corresponds to
|
||||
* the limit, so we must fetch the remaining bits ourselves.
|
||||
*
|
||||
* The 80386 LGDT instruction assumes a 48-bit operand: a 16-bit limit followed by a 32-bit base address,
|
||||
* but it ignores the last 8 bits of the base address if the OPERAND size is 16 bits; we interpret that to
|
||||
* mean that the 24-bit base address should be zero-extended to 32 bits.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
|
|
@ -1460,10 +1464,15 @@ X86.fnLGDT = function LGDT(dst, src)
|
|||
X86.opInvalid.call(this);
|
||||
} else {
|
||||
/*
|
||||
* It shouldn't hurt to always fetch 32 bits of physical memory, which we'll then
|
||||
* mask with either a 24-bit or a 32-bit mask.
|
||||
* Hopefully it won't hurt to always fetch a 32-bit base address (even on an 80286), which we then
|
||||
* mask apppropriately.
|
||||
*/
|
||||
this.addrGDT = this.getLong(this.regEA + 2) & (this.dataMask | (this.dataMask << 8));
|
||||
/*
|
||||
* An idiosyncrasy of our ModRM decoders is that, if the OPERAND size is 32 bits, then it will have
|
||||
* fetched a 32-bit dst operand; we mask off those extra bits now.
|
||||
*/
|
||||
dst &= 0xffff;
|
||||
this.addrGDTLimit = this.addrGDT + dst;
|
||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||
this.nStepCycles -= 11;
|
||||
|
|
@ -1495,9 +1504,13 @@ X86.fnLGS = function LGS(dst, src)
|
|||
*
|
||||
* op=0x0F,0x01,reg=0x3 (GRP7:LIDT)
|
||||
*
|
||||
* The 80286 LIDT instruction expects a 40-bit operand: a 16-bit limit, followed by a 24-bit address
|
||||
* (or a 32-bit address in 32-bit mode); the ModRM decoder has already supplied the first word of the
|
||||
* operand (in dst), which corresponds to the limit, so we must fetch the remaining bits ourselves.
|
||||
* The 80286 LIDT instruction assumes a 40-bit operand: a 16-bit limit followed by a 24-bit base address;
|
||||
* the ModRM decoder has already supplied the first word of the operand (in dst), which corresponds to
|
||||
* the limit, so we must fetch the remaining bits ourselves.
|
||||
*
|
||||
* The 80386 LIDT instruction assumes a 48-bit operand: a 16-bit limit followed by a 32-bit base address,
|
||||
* but it ignores the last 8 bits of the base address if the OPERAND size is 16 bits; we interpret that to
|
||||
* mean that the 24-bit base address should be zero-extended to 32 bits.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} dst
|
||||
|
|
@ -1510,10 +1523,15 @@ X86.fnLIDT = function LIDT(dst, src)
|
|||
X86.opInvalid.call(this);
|
||||
} else {
|
||||
/*
|
||||
* It shouldn't hurt to always fetch 32 bits of physical memory, which we'll then
|
||||
* mask with either a 24-bit or a 32-bit mask.
|
||||
* Hopefully it won't hurt to always fetch a 32-bit base address (even on an 80286), which we then
|
||||
* mask apppropriately.
|
||||
*/
|
||||
this.addrIDT = this.getLong(this.regEA + 2) & (this.dataMask | (this.dataMask << 8));
|
||||
/*
|
||||
* An idiosyncrasy of our ModRM decoders is that, if the OPERAND size is 32 bits, then it will have
|
||||
* fetched a 32-bit dst operand; we mask off those extra bits now.
|
||||
*/
|
||||
dst &= 0xffff;
|
||||
this.addrIDTLimit = this.addrIDT + dst;
|
||||
this.opFlags |= X86.OPFLAG.NOWRITE;
|
||||
this.nStepCycles -= 12;
|
||||
|
|
|
|||
|
|
@ -2098,6 +2098,10 @@ X86.opMOVwsr = function MOVwsr()
|
|||
}
|
||||
/*
|
||||
* Like other MOV operations, the destination does not need to be read, just written.
|
||||
*
|
||||
* TODO: Confirm this instruction's behavior on the 80386; ie, if a 32-bit OPERAND size is
|
||||
* in effect, does it still write only 16 bits? If so, we must add a setDataSize(2) override.
|
||||
* Confirm for both register and memory destinations.
|
||||
*/
|
||||
this.opFlags |= X86.OPFLAG.NOREAD;
|
||||
this.aOpModMemWord[bModRM].call(this, X86.fnMOVxx);
|
||||
|
|
|
|||
|
|
@ -157,12 +157,18 @@ X86Seg.prototype.loadProt = function loadProt(sel, fSuppress)
|
|||
*/
|
||||
sel &= 0xffff;
|
||||
|
||||
/*
|
||||
* When comparing descriptor addresses, we must be mindful that any addresses above 2Gb will be negative;
|
||||
* that in itself is not a problem UNLESS the descriptor table straddles the 2Gb boundary, meaning the
|
||||
* starting address is positive but the ending (limit) address is negative. Although that situation is
|
||||
* highly unlikely, the safest thing to do is coerce the bounding addresses to unsigned values, using ">>> 0."
|
||||
*/
|
||||
if (!(sel & X86.SEL.LDT)) {
|
||||
addrDT = cpu.addrGDT;
|
||||
addrDTLimit = cpu.addrGDTLimit;
|
||||
addrDT = cpu.addrGDT >>> 0;
|
||||
addrDTLimit = cpu.addrGDTLimit >>> 0;
|
||||
} else {
|
||||
addrDT = cpu.segLDT.base;
|
||||
addrDTLimit = addrDT + cpu.segLDT.limit;
|
||||
addrDT = cpu.segLDT.base >>> 0;
|
||||
addrDTLimit = addrDT + cpu.segLDT.limit; // segment limit properties are already coerced unsigned
|
||||
}
|
||||
/*
|
||||
* The ROM BIOS POST executes some test code in protected-mode without properly initializing the LDT,
|
||||
|
|
|
|||
Loading…
Reference in a new issue