Fixed LGDT and LIDT, fixed read-only memory, and fixed mode transition tests

This commit is contained in:
Jeff Parsons 2015-05-06 16:24:28 -07:00 committed by jeffpar
commit cfa4e0207f
5 changed files with 158 additions and 104 deletions

View file

@ -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)

View file

@ -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;

View file

@ -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);

View file

@ -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,