Fix SGDT/SIDT for the 80386
This commit is contained in:
parent
523b7e72f5
commit
10d2551bc0
2 changed files with 104 additions and 82 deletions
|
|
@ -454,8 +454,7 @@
|
||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
||||||
<xsl:template match="manifest[not(@ref)]" mode="component">
|
<xsl:template match="manifest[not(@ref)]" mode="component">
|
||||||
<xsl:param name="disk"><xsl:value-of select="@disk"/></xsl:param>
|
<xsl:param name="disk"><xsl:if test="@disk"><xsl:value-of select="@disk"/></xsl:if><xsl:if test="not(@disk)">*</xsl:if></xsl:param>
|
||||||
<xsl:if test="$disk != ''">
|
|
||||||
<xsl:variable name="prefix">
|
<xsl:variable name="prefix">
|
||||||
<xsl:if test="title/@prefix"><xsl:value-of select="title/@prefix"/><xsl:text>: </xsl:text></xsl:if>
|
<xsl:if test="title/@prefix"><xsl:value-of select="title/@prefix"/><xsl:text>: </xsl:text></xsl:if>
|
||||||
</xsl:variable>
|
</xsl:variable>
|
||||||
|
|
@ -494,7 +493,6 @@
|
||||||
</xsl:if>
|
</xsl:if>
|
||||||
</xsl:if>
|
</xsl:if>
|
||||||
</xsl:for-each>
|
</xsl:for-each>
|
||||||
</xsl:if>
|
|
||||||
</xsl:template>
|
</xsl:template>
|
||||||
|
|
||||||
<xsl:template match="name">
|
<xsl:template match="name">
|
||||||
|
|
|
||||||
|
|
@ -2883,11 +2883,14 @@ X86.fnSGDT = function(dst, src)
|
||||||
X86.opInvalid.call(this);
|
X86.opInvalid.call(this);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* We don't need to setShort() the first word of the operand, because the ModRM group decoder that
|
* We don't need to set the first word of the operand, because the ModRM group decoder that calls us
|
||||||
* calls us does that automatically with the value we return (dst).
|
* does that automatically with the value we return (dst).
|
||||||
*/
|
*/
|
||||||
dst = this.addrGDTLimit - this.addrGDT;
|
dst = this.addrGDTLimit - this.addrGDT;
|
||||||
this.assert(!(dst & ~0xffff));
|
this.assert(!(dst & ~0xffff));
|
||||||
|
|
||||||
|
var addr = this.addrGDT;
|
||||||
|
if (this.model == X86.MODEL_80286) {
|
||||||
/*
|
/*
|
||||||
* We previously left the 6th byte of the target operand "undefined". But it turns out we have to set
|
* We previously left the 6th byte of the target operand "undefined". But it turns out we have to set
|
||||||
* it to *something*, because there's processor detection in PC-DOS 7.0 (at least in the SETUP portion)
|
* it to *something*, because there's processor detection in PC-DOS 7.0 (at least in the SETUP portion)
|
||||||
|
|
@ -2916,24 +2919,41 @@ X86.fnSGDT = function(dst, src)
|
||||||
* 145E:4BC2 9D POPF
|
* 145E:4BC2 9D POPF
|
||||||
* 145E:4BC3 CB RETF
|
* 145E:4BC3 CB RETF
|
||||||
*
|
*
|
||||||
* This code is expecting SGDT on an 80286 to set the 6th "undefined" byte to 0xFF.
|
* This code is expecting SGDT on an 80286 to set the 6th "undefined" byte to 0xFF, so that's what we do.
|
||||||
*
|
|
||||||
* The 80386 adds an additional wrinkle: the 6th byte must be 0x00 if the OPERAND size is 2, whereas
|
|
||||||
* it must passed through if the OPERAND size is 4.
|
|
||||||
*
|
|
||||||
* In addition, when the OPERAND size is 4, the ModRM group decoder will call setLong(dst) rather than
|
|
||||||
* setShort(dst); we could fix that by forcing the dataSize to 2, but it seems simpler to set the high
|
|
||||||
* bits (16-31) of dst to match the low bits (0-15) of addr, so that the caller will harmlessly rewrite
|
|
||||||
* what we already wrote with the setLong() below.
|
|
||||||
*/
|
*/
|
||||||
var addr = this.addrGDT;
|
|
||||||
if (this.model == X86.MODEL_80286) {
|
|
||||||
addr |= (0xff000000|0);
|
addr |= (0xff000000|0);
|
||||||
}
|
}
|
||||||
else if (this.model >= X86.MODEL_80386) {
|
else if (this.model >= X86.MODEL_80386) {
|
||||||
|
/*
|
||||||
|
* The 80386 added another wrinkle: Intel's documentation claimed that the 6th byte is either set to zero
|
||||||
|
* or the high byte of the BASE field, depending on the OPERAND size; from the "INTEL 80386 PROGRAMMER'S
|
||||||
|
* REFERENCE MANUAL 1986":
|
||||||
|
*
|
||||||
|
* The LIMIT field of the [GDTR or IDTR] register is assigned to the first word at the effective address.
|
||||||
|
* If the operand-size attribute is 32 bits, the next three bytes are assigned the BASE field of the
|
||||||
|
* register, and the fourth byte is written with zero. The last byte is undefined. Otherwise, if the
|
||||||
|
* operand-size attribute is 16 bits, the next 4 bytes are assigned the 32-bit BASE field of the register.
|
||||||
|
*
|
||||||
|
* However, Intel obviously meant the reverse (ie, that the BASE field is truncated when using a 16-bit
|
||||||
|
* OPERAND size, not when using a 32-bit OPERAND size).
|
||||||
|
*
|
||||||
|
* UPDATE: Thanks to Michal Necasek, we now know that the: "386 in reality does not pay attention to the
|
||||||
|
* operand size (despite Intel's claims to the contrary). In fact Windows 3.11/Win32s relies on it -- at least
|
||||||
|
* in some configurations, it will execute SGDT in 16-bit code and will crash if all 6 bytes aren't stored."
|
||||||
|
*/
|
||||||
if (this.sizeData == 2) {
|
if (this.sizeData == 2) {
|
||||||
addr &= 0x00ffffff;
|
/*
|
||||||
|
* Based on the above information, we no longer mask the 6th byte on the 80386 when the OPERAND size is 2.
|
||||||
|
*
|
||||||
|
* addr &= 0x00ffffff;
|
||||||
|
*/
|
||||||
} else {
|
} else {
|
||||||
|
/*
|
||||||
|
* When the OPERAND size is 4, our ModRM group decoder will call setLong(dst) rather than setShort(dst);
|
||||||
|
* we could fix that by calling setDataSize(2), but it seems safer/simpler to set the high bits (16-31)
|
||||||
|
* of dst to match the low bits (0-15) of addr, so that the caller will harmlessly rewrite what we are
|
||||||
|
* already writing with the setLong() below.
|
||||||
|
*/
|
||||||
dst |= (addr << 16);
|
dst |= (addr << 16);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3277,8 +3297,8 @@ X86.fnSIDT = function(dst, src)
|
||||||
X86.opInvalid.call(this);
|
X86.opInvalid.call(this);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* We don't need to setShort() the first word of the operand, because the ModRM group decoder that calls
|
* We don't need to set the first word of the operand, because the ModRM group decoder that calls us
|
||||||
* us does that automatically with the value we return (dst).
|
* does that automatically with the value we return (dst).
|
||||||
*/
|
*/
|
||||||
dst = this.addrIDTLimit - this.addrIDT;
|
dst = this.addrIDTLimit - this.addrIDT;
|
||||||
this.assert(!(dst & ~0xffff));
|
this.assert(!(dst & ~0xffff));
|
||||||
|
|
@ -3292,7 +3312,11 @@ X86.fnSIDT = function(dst, src)
|
||||||
}
|
}
|
||||||
else if (this.model >= X86.MODEL_80386) {
|
else if (this.model >= X86.MODEL_80386) {
|
||||||
if (this.sizeData == 2) {
|
if (this.sizeData == 2) {
|
||||||
addr &= 0x00ffffff;
|
/*
|
||||||
|
* Based on the SGDT information above, we no longer mask the 6th byte when the OPERAND size is 2.
|
||||||
|
*
|
||||||
|
* addr &= 0x00ffffff;
|
||||||
|
*/
|
||||||
} else {
|
} else {
|
||||||
dst |= (addr << 16);
|
dst |= (addr << 16);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue