2001-10-03 17:10:38 +04:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2001-10-10 01:15:14 +04:00
|
|
|
// $Id: protect_ctrl.cc,v 1.10 2001-10-09 21:15:14 bdenney Exp $
|
2001-10-03 17:10:38 +04:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
2001-04-10 06:20:02 +04:00
|
|
|
// Copyright (C) 2001 MandrakeSoft S.A.
|
2001-04-10 05:04:59 +04:00
|
|
|
//
|
|
|
|
// MandrakeSoft S.A.
|
|
|
|
// 43, rue d'Aboukir
|
|
|
|
// 75002 Paris - France
|
|
|
|
// http://www.linux-mandrake.com/
|
|
|
|
// http://www.mandrakesoft.com/
|
|
|
|
//
|
|
|
|
// This library is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU Lesser General Public
|
|
|
|
// License as published by the Free Software Foundation; either
|
|
|
|
// version 2 of the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This library is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// Lesser General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
|
|
// License along with this library; if not, write to the Free Software
|
|
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2001-05-24 22:46:34 +04:00
|
|
|
#define NEED_CPU_REG_SHORTCUTS 1
|
2001-04-10 05:04:59 +04:00
|
|
|
#include "bochs.h"
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
#define LOG_THIS BX_CPU_THIS_PTR
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
BX_CPU_C::ARPL_EwGw(BxInstruction_t *i)
|
|
|
|
{
|
|
|
|
#if BX_CPU_LEVEL < 2
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("ARPL_EwRw: not supported on 8086!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
#else /* 286+ */
|
|
|
|
|
|
|
|
Bit16u op2_16, op1_16;
|
|
|
|
|
|
|
|
|
|
|
|
if (protected_mode()) {
|
|
|
|
/* op1_16 is a register or memory reference */
|
|
|
|
if (i->mod == 0xc0) {
|
|
|
|
op1_16 = BX_READ_16BIT_REG(i->rm);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* pointer, segment address pair */
|
|
|
|
read_RMW_virtual_word(i->seg, i->rm_addr, &op1_16);
|
|
|
|
}
|
|
|
|
|
|
|
|
op2_16 = BX_READ_16BIT_REG(i->nnn);
|
|
|
|
|
|
|
|
if ( (op1_16 & 0x03) < (op2_16 & 0x03) ) {
|
|
|
|
op1_16 = (op1_16 & 0xfffc) | (op2_16 & 0x03);
|
|
|
|
/* now write back to destination */
|
|
|
|
if (i->mod == 0xc0) {
|
|
|
|
if (i->os_32) {
|
|
|
|
// if 32bit opsize, then 0xff3f is or'd into
|
|
|
|
// upper 16bits of register
|
|
|
|
Bit32u op1_32;
|
|
|
|
|
|
|
|
op1_32 = BX_READ_32BIT_REG(i->rm);
|
|
|
|
op1_32 = (op1_32 & 0xffff0000) | op1_16;
|
|
|
|
op1_32 |= 0xff3f0000;
|
|
|
|
BX_WRITE_32BIT_REG(i->rm, op1_32);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BX_WRITE_16BIT_REG(i->rm, op1_16);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
write_RMW_virtual_word(op1_16);
|
|
|
|
}
|
|
|
|
set_ZF(1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
set_ZF(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// ARPL not recognized in real or v8086 mode
|
|
|
|
UndefinedOpcode(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
BX_CPU_C::LAR_GvEw(BxInstruction_t *i)
|
|
|
|
{
|
|
|
|
/* for 16 bit operand size mode */
|
|
|
|
Bit16u raw_selector;
|
|
|
|
bx_descriptor_t descriptor;
|
|
|
|
bx_selector_t selector;
|
|
|
|
Bit32u dword1, dword2;
|
|
|
|
|
|
|
|
|
2001-05-30 22:56:02 +04:00
|
|
|
if (v8086_mode()) BX_PANIC(("protect_ctrl: v8086 mode unsupported"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
if (real_mode()) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("LAR_GvEw: not recognized in real mode"));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (i->mod == 0xc0) {
|
|
|
|
raw_selector = BX_READ_16BIT_REG(i->rm);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* pointer, segment address pair */
|
|
|
|
read_virtual_word(i->seg, i->rm_addr, &raw_selector);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if selector null, clear ZF and done */
|
|
|
|
if ( (raw_selector & 0xfffc) == 0 ) {
|
|
|
|
set_ZF(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
parse_selector(raw_selector, &selector);
|
|
|
|
|
|
|
|
if ( !fetch_raw_descriptor2(&selector, &dword1, &dword2) ) {
|
|
|
|
/* not within descriptor table */
|
|
|
|
set_ZF(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
parse_descriptor(dword1, dword2, &descriptor);
|
|
|
|
|
|
|
|
if (descriptor.valid==0) {
|
|
|
|
set_ZF(0);
|
2001-05-30 22:56:02 +04:00
|
|
|
//BX_DEBUG(("lar(): descriptor valid bit cleared"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if source selector is visible at CPL & RPL,
|
|
|
|
* within the descriptor table, and of type accepted by LAR instruction,
|
|
|
|
* then load register with segment limit and set ZF
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ( descriptor.segment ) { /* normal segment */
|
|
|
|
if ( descriptor.u.segment.executable && descriptor.u.segment.c_ed ) {
|
|
|
|
/* ignore DPL for conforming segments */
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if ( (descriptor.dpl<CPL) || (descriptor.dpl<selector.rpl) ) {
|
|
|
|
set_ZF(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
set_ZF(1);
|
|
|
|
if (i->os_32) {
|
|
|
|
/* masked by 00FxFF00, where x is undefined */
|
|
|
|
BX_WRITE_32BIT_REG(i->nnn, dword2 & 0x00ffff00);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BX_WRITE_16BIT_REG(i->nnn, dword2 & 0xff00);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else { /* system or gate segment */
|
|
|
|
switch ( descriptor.type ) {
|
|
|
|
case 1: /* available TSS */
|
|
|
|
case 2: /* LDT */
|
|
|
|
case 3: /* busy TSS */
|
|
|
|
case 4: /* 286 call gate */
|
|
|
|
case 5: /* task gate */
|
|
|
|
#if BX_CPU_LEVEL >= 3
|
|
|
|
case 9: /* available 32bit TSS */
|
|
|
|
case 11: /* busy 32bit TSS */
|
|
|
|
case 12: /* 32bit call gate */
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
default: /* rest not accepted types to LAR */
|
|
|
|
set_ZF(0);
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_DEBUG(("lar(): not accepted type"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( (descriptor.dpl<CPL) || (descriptor.dpl<selector.rpl) ) {
|
|
|
|
set_ZF(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
set_ZF(1);
|
|
|
|
if (i->os_32) {
|
|
|
|
/* masked by 00FxFF00, where x is undefined ??? */
|
|
|
|
BX_WRITE_32BIT_REG(i->nnn, dword2 & 0x00ffff00);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BX_WRITE_16BIT_REG(i->nnn, dword2 & 0xff00);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
BX_CPU_C::LSL_GvEw(BxInstruction_t *i)
|
|
|
|
{
|
|
|
|
/* for 16 bit operand size mode */
|
|
|
|
Bit16u raw_selector;
|
|
|
|
Bit32u limit32;
|
|
|
|
//bx_descriptor_t descriptor;
|
|
|
|
bx_selector_t selector;
|
|
|
|
Bit32u dword1, dword2;
|
|
|
|
Bit32u descriptor_dpl;
|
|
|
|
|
2001-05-30 22:56:02 +04:00
|
|
|
if (v8086_mode()) BX_PANIC(("protect_ctrl: v8086 mode unsupported"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
|
|
|
|
if (real_mode()) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("LSL_GvEw: not recognized in real mode"));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i->mod == 0xc0) {
|
|
|
|
raw_selector = BX_READ_16BIT_REG(i->rm);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* pointer, segment address pair */
|
|
|
|
read_virtual_word(i->seg, i->rm_addr, &raw_selector);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* if selector null, clear ZF and done */
|
|
|
|
if ( (raw_selector & 0xfffc) == 0 ) {
|
|
|
|
set_ZF(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
parse_selector(raw_selector, &selector);
|
|
|
|
|
|
|
|
if ( !fetch_raw_descriptor2(&selector, &dword1, &dword2) ) {
|
|
|
|
/* not within descriptor table */
|
|
|
|
set_ZF(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//parse_descriptor(dword1, dword2, &descriptor);
|
|
|
|
|
|
|
|
descriptor_dpl = (dword2 >> 13) & 0x03;
|
|
|
|
|
|
|
|
if ( (dword2 & 0x00001000) == 0 ) { // system segment
|
|
|
|
Bit32u type;
|
|
|
|
|
|
|
|
type = (dword2 >> 8) & 0x0000000f;
|
|
|
|
switch (type) {
|
|
|
|
case 1: // 16bit TSS
|
|
|
|
case 3: // 16bit TSS
|
|
|
|
case 2: // LDT
|
|
|
|
case 9: // 32bit TSS G00A
|
|
|
|
case 11:// 32bit TSS G00A
|
|
|
|
limit32 = (dword1 & 0x0000ffff) | (dword2 & 0x000f0000);
|
|
|
|
if ( dword2 & 0x00800000 )
|
|
|
|
limit32 = (limit32 << 12) | 0x00000fff;
|
|
|
|
if ( (descriptor_dpl<CPL) || (descriptor_dpl<selector.rpl) ) {
|
|
|
|
set_ZF(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
goto lsl_ok;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
set_ZF(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else { // data & code segment
|
|
|
|
limit32 = (dword1 & 0x0000ffff) | (dword2 & 0x000f0000);
|
|
|
|
if ( dword2 & 0x00800000 )
|
|
|
|
limit32 = (limit32 << 12) | 0x00000fff;
|
|
|
|
if ( (dword2 & 0x00000c00) == 0x00000c00 ) {
|
|
|
|
// conforming code segment, no check done
|
|
|
|
goto lsl_ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( (descriptor_dpl<CPL) || (descriptor_dpl<selector.rpl) ) {
|
|
|
|
set_ZF(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
goto lsl_ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
lsl_ok:
|
|
|
|
/* all checks pass, limit32 is now byte granular, write to op1 */
|
|
|
|
set_ZF(1);
|
|
|
|
|
|
|
|
if (i->os_32)
|
|
|
|
BX_WRITE_32BIT_REG(i->nnn, limit32)
|
|
|
|
else
|
|
|
|
// chop off upper 16 bits
|
|
|
|
BX_WRITE_16BIT_REG(i->nnn, (Bit16u) limit32)
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
BX_CPU_C::SLDT_Ew(BxInstruction_t *i)
|
|
|
|
{
|
|
|
|
#if BX_CPU_LEVEL < 2
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("SLDT_Ew: not supported on 8086!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
#else
|
2001-05-30 22:56:02 +04:00
|
|
|
if (v8086_mode()) BX_PANIC(("protect_ctrl: v8086 mode unsupported"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
if (real_mode()) {
|
|
|
|
/* not recognized in real address mode */
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_ERROR(("SLDT_Ew: encountered in real mode."));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Bit16u val16;
|
|
|
|
|
|
|
|
val16 = BX_CPU_THIS_PTR ldtr.selector.value;
|
|
|
|
if (i->mod == 0xc0) {
|
|
|
|
BX_WRITE_16BIT_REG(i->rm, val16);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
write_virtual_word(i->seg, i->rm_addr, &val16);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
BX_CPU_C::STR_Ew(BxInstruction_t *i)
|
|
|
|
{
|
2001-05-30 22:56:02 +04:00
|
|
|
if (v8086_mode()) BX_PANIC(("protect_ctrl: v8086 mode unsupported"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
if (real_mode()) {
|
|
|
|
// not recognized in real address mode
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("STR_Ew: encountered in real mode."));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Bit16u val16;
|
|
|
|
|
|
|
|
val16 = BX_CPU_THIS_PTR tr.selector.value;
|
|
|
|
if (i->mod == 0xc0) {
|
|
|
|
BX_WRITE_16BIT_REG(i->rm, val16);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
write_virtual_word(i->seg, i->rm_addr, &val16);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
BX_CPU_C::LLDT_Ew(BxInstruction_t *i)
|
|
|
|
{
|
|
|
|
#if BX_CPU_LEVEL < 2
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("LLDT_Ew: not supported on 8086!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
#else
|
2001-05-30 22:56:02 +04:00
|
|
|
if (v8086_mode()) BX_PANIC(("protect_ctrl: v8086 mode unsupported"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
|
|
|
if (real_mode()) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("lldt: not recognized in real mode"));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else { /* protected mode */
|
|
|
|
bx_descriptor_t descriptor;
|
|
|
|
bx_selector_t selector;
|
|
|
|
Bit16u raw_selector;
|
|
|
|
Bit32u dword1, dword2;
|
|
|
|
|
|
|
|
|
|
|
|
/* #GP(0) if the current privilege level is not 0 */
|
|
|
|
if (CPL != 0) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("LLDT: CPL != 0"));
|
2001-04-10 05:04:59 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i->mod == 0xc0) {
|
|
|
|
raw_selector = BX_READ_16BIT_REG(i->rm);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
read_virtual_word(i->seg, i->rm_addr, &raw_selector);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if selector is NULL, invalidate and done */
|
|
|
|
if ((raw_selector & 0xfffc) == 0) {
|
|
|
|
BX_CPU_THIS_PTR ldtr.selector.value = raw_selector;
|
|
|
|
BX_CPU_THIS_PTR ldtr.cache.valid = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* parse fields in selector */
|
|
|
|
parse_selector(raw_selector, &selector);
|
|
|
|
|
|
|
|
// #GP(selector) if the selector operand does not point into GDT
|
|
|
|
if (selector.ti != 0) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_ERROR(("LLDT: selector.ti != 0"));
|
2001-04-10 05:04:59 +04:00
|
|
|
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((selector.index*8 + 7) > BX_CPU_THIS_PTR gdtr.limit) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("lldt: GDT: index > limit"));
|
2001-04-10 05:04:59 +04:00
|
|
|
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
access_linear(BX_CPU_THIS_PTR gdtr.base + selector.index*8, 4, 0,
|
|
|
|
BX_READ, &dword1);
|
|
|
|
access_linear(BX_CPU_THIS_PTR gdtr.base + selector.index*8 + 4, 4, 0,
|
|
|
|
BX_READ, &dword2);
|
|
|
|
|
|
|
|
parse_descriptor(dword1, dword2, &descriptor);
|
|
|
|
|
|
|
|
/* if selector doesn't point to an LDT descriptor #GP(selector) */
|
|
|
|
if ( (descriptor.valid==0) ||
|
|
|
|
descriptor.segment ||
|
|
|
|
(descriptor.type!=2) ) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_ERROR(("lldt: doesn't point to an LDT descriptor!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* #NP(selector) if LDT descriptor is not present */
|
|
|
|
if (descriptor.p==0) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_ERROR(("lldt: LDT descriptor not present!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
exception(BX_NP_EXCEPTION, raw_selector & 0xfffc, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (descriptor.u.ldt.limit < 7) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_ERROR(("lldt: ldtr.limit < 7"));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR ldtr.selector = selector;
|
|
|
|
BX_CPU_THIS_PTR ldtr.cache = descriptor;
|
|
|
|
BX_CPU_THIS_PTR ldtr.cache.valid = 1;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
BX_CPU_C::LTR_Ew(BxInstruction_t *i)
|
|
|
|
{
|
|
|
|
#if BX_CPU_LEVEL < 2
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("LTR_Ew: not supported on 8086!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
#else
|
2001-05-30 22:56:02 +04:00
|
|
|
if (v8086_mode()) BX_PANIC(("protect_ctrl: v8086 mode unsupported"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
|
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
|
|
|
if (protected_mode()) {
|
|
|
|
bx_descriptor_t descriptor;
|
|
|
|
bx_selector_t selector;
|
|
|
|
Bit16u raw_selector;
|
|
|
|
Bit32u dword1, dword2;
|
|
|
|
|
|
|
|
|
|
|
|
/* #GP(0) if the current privilege level is not 0 */
|
|
|
|
if (CPL != 0) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("LTR: CPL != 0"));
|
2001-04-10 05:04:59 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i->mod == 0xc0) {
|
|
|
|
raw_selector = BX_READ_16BIT_REG(i->rm);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
read_virtual_word(i->seg, i->rm_addr, &raw_selector);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if selector is NULL, invalidate and done */
|
|
|
|
if ((raw_selector & 0xfffc) == 0) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("ltr: loading with NULL selector!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
/* if this is OK, then invalidate and load selector & descriptor cache */
|
|
|
|
/* load here */
|
|
|
|
BX_CPU_THIS_PTR tr.selector.value = raw_selector;
|
|
|
|
BX_CPU_THIS_PTR tr.cache.valid = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* parse fields in selector, then check for null selector */
|
|
|
|
parse_selector(raw_selector, &selector);
|
|
|
|
|
|
|
|
if (selector.ti) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("ltr: selector.ti != 0"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fetch 2 dwords of descriptor; call handles out of limits checks */
|
|
|
|
fetch_raw_descriptor(&selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
|
|
|
|
|
|
|
parse_descriptor(dword1, dword2, &descriptor);
|
|
|
|
|
|
|
|
/* #GP(selector) if object is not a TSS or is already busy */
|
|
|
|
if ( (descriptor.valid==0) || descriptor.segment ||
|
|
|
|
(descriptor.type!=1 && descriptor.type!=9) ) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("ltr: doesn't point to an available TSS descriptor!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc, 0); /* 0 ??? */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* #NP(selector) if TSS descriptor is not present */
|
|
|
|
if (descriptor.p==0) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("ltr: LDT descriptor not present!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
exception(BX_NP_EXCEPTION, raw_selector & 0xfffc, 0); /* 0 ??? */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (descriptor.type==1 && descriptor.u.tss286.limit<43) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("ltr:286TSS: loading tr.limit < 43"));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
else if (descriptor.type==9 && descriptor.u.tss386.limit_scaled<103) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("ltr:386TSS: loading tr.limit < 103"));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR tr.selector = selector;
|
|
|
|
BX_CPU_THIS_PTR tr.cache = descriptor;
|
|
|
|
BX_CPU_THIS_PTR tr.cache.valid = 1;
|
2001-10-10 01:15:14 +04:00
|
|
|
// tr.cache.type should not have busy bit, or it would not get
|
|
|
|
// through the conditions above.
|
|
|
|
BX_ASSERT((BX_CPU_THIS_PTR tr.cache.type & 2) == 0);
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* mark as busy */
|
|
|
|
dword2 |= 0x00000200; /* set busy bit */
|
|
|
|
access_linear(BX_CPU_THIS_PTR gdtr.base + selector.index*8 + 4, 4, 0,
|
|
|
|
BX_WRITE, &dword2);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("ltr_ew: not recognized in real-mode!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
BX_CPU_C::VERR_Ew(BxInstruction_t *i)
|
|
|
|
{
|
|
|
|
/* for 16 bit operand size mode */
|
|
|
|
Bit16u raw_selector;
|
|
|
|
bx_descriptor_t descriptor;
|
|
|
|
bx_selector_t selector;
|
|
|
|
Bit32u dword1, dword2;
|
|
|
|
|
2001-05-30 22:56:02 +04:00
|
|
|
if (v8086_mode()) BX_PANIC(("protect_ctrl: v8086 mode unsupported"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
|
|
|
|
if (real_mode()) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("VERR_Ew: not recognized in real mode"));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i->mod == 0xc0) {
|
|
|
|
raw_selector = BX_READ_16BIT_REG(i->rm);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* pointer, segment address pair */
|
|
|
|
read_virtual_word(i->seg, i->rm_addr, &raw_selector);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if selector null, clear ZF and done */
|
|
|
|
if ( (raw_selector & 0xfffc) == 0 ) {
|
|
|
|
set_ZF(0);
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_ERROR(("VERR: null selector"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if source selector is visible at CPL & RPL,
|
|
|
|
* within the descriptor table, and of type accepted by VERR instruction,
|
|
|
|
* then load register with segment limit and set ZF */
|
|
|
|
parse_selector(raw_selector, &selector);
|
|
|
|
|
|
|
|
if ( !fetch_raw_descriptor2(&selector, &dword1, &dword2) ) {
|
|
|
|
/* not within descriptor table */
|
|
|
|
set_ZF(0);
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_ERROR(("VERR: not in table"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
parse_descriptor(dword1, dword2, &descriptor);
|
|
|
|
|
|
|
|
if ( descriptor.segment==0 ) { /* system or gate descriptor */
|
|
|
|
set_ZF(0); /* inaccessible */
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_ERROR(("VERR: system descriptor"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( descriptor.valid==0 ) {
|
|
|
|
set_ZF(0);
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("VERR: valid bit cleared"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* normal data/code segment */
|
|
|
|
if ( descriptor.u.segment.executable ) { /* code segment */
|
|
|
|
/* ignore DPL for readable conforming segments */
|
|
|
|
if ( descriptor.u.segment.c_ed &&
|
|
|
|
descriptor.u.segment.r_w) {
|
|
|
|
set_ZF(1); /* accessible */
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("VERR: conforming code, OK"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ( descriptor.u.segment.r_w==0 ) {
|
|
|
|
set_ZF(0); /* inaccessible */
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("VERR: code not readable"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* readable, non-conforming code segment */
|
|
|
|
if ( (descriptor.dpl<CPL) || (descriptor.dpl<selector.rpl) ) {
|
|
|
|
set_ZF(0); /* inaccessible */
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("VERR: non-coforming code not withing priv level"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
set_ZF(1); /* accessible */
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("VERR: code seg readable"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
else { /* data segment */
|
|
|
|
if ( (descriptor.dpl<CPL) || (descriptor.dpl<selector.rpl) ) {
|
|
|
|
set_ZF(0); /* not accessible */
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("VERR: data seg not withing priv level"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
set_ZF(1); /* accessible */
|
2001-06-27 23:16:01 +04:00
|
|
|
BX_ERROR(("VERR: data segment OK"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
BX_CPU_C::VERW_Ew(BxInstruction_t *i)
|
|
|
|
{
|
|
|
|
/* for 16 bit operand size mode */
|
|
|
|
Bit16u raw_selector;
|
|
|
|
bx_descriptor_t descriptor;
|
|
|
|
bx_selector_t selector;
|
|
|
|
Bit32u dword1, dword2;
|
|
|
|
|
2001-05-30 22:56:02 +04:00
|
|
|
if (v8086_mode()) BX_PANIC(("protect_ctrl: v8086 mode unsupported"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
|
|
|
|
if (real_mode()) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("VERW_Ew: not recognized in real mode"));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i->mod == 0xc0) {
|
|
|
|
raw_selector = BX_READ_16BIT_REG(i->rm);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* pointer, segment address pair */
|
|
|
|
read_virtual_word(i->seg, i->rm_addr, &raw_selector);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if selector null, clear ZF and done */
|
|
|
|
if ( (raw_selector & 0xfffc) == 0 ) {
|
|
|
|
set_ZF(0);
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_ERROR(("VERW: null selector"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if source selector is visible at CPL & RPL,
|
|
|
|
* within the descriptor table, and of type accepted by VERW instruction,
|
|
|
|
* then load register with segment limit and set ZF */
|
|
|
|
parse_selector(raw_selector, &selector);
|
|
|
|
|
|
|
|
if ( !fetch_raw_descriptor2(&selector, &dword1, &dword2) ) {
|
|
|
|
/* not within descriptor table */
|
|
|
|
set_ZF(0);
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_ERROR(("VERW: not in table"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
parse_descriptor(dword1, dword2, &descriptor);
|
|
|
|
|
|
|
|
/* rule out system segments & code segments */
|
|
|
|
if ( descriptor.segment==0 || descriptor.u.segment.executable ) {
|
|
|
|
set_ZF(0);
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_ERROR(("VERW: system seg or code"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( descriptor.valid==0 ) {
|
|
|
|
set_ZF(0);
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("VERW: valid bit cleared"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* data segment */
|
|
|
|
if ( descriptor.u.segment.r_w ) { /* writable */
|
|
|
|
if ( (descriptor.dpl<CPL) || (descriptor.dpl<selector.rpl) ) {
|
|
|
|
set_ZF(0); /* not accessible */
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("VERW: writable data seg not within priv level"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
set_ZF(1); /* accessible */
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_ERROR(("VERW: data seg writable"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
set_ZF(0); /* not accessible */
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("VERW: data seg not writable"));
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
BX_CPU_C::SGDT_Ms(BxInstruction_t *i)
|
|
|
|
{
|
|
|
|
#if BX_CPU_LEVEL < 2
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("SGDT_Ms: not supported on 8086!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
#else
|
|
|
|
Bit16u limit_16;
|
|
|
|
Bit32u base_32;
|
|
|
|
|
2001-05-30 22:56:02 +04:00
|
|
|
if (v8086_mode()) BX_PANIC(("protect_ctrl: v8086 mode unsupported"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
|
|
|
|
/* op1 is a register or memory reference */
|
|
|
|
if (i->mod == 0xc0) {
|
|
|
|
/* undefined opcode exception */
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("SGDT_Ms: use of register is undefined opcode."));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
limit_16 = BX_CPU_THIS_PTR gdtr.limit;
|
|
|
|
base_32 = BX_CPU_THIS_PTR gdtr.base;
|
|
|
|
#if BX_CPU_LEVEL == 2
|
|
|
|
base_32 |= 0xff000000; /* ??? */
|
|
|
|
#else /* 386+ */
|
|
|
|
/* 32bit processors always write 32bits of base */
|
|
|
|
#endif
|
|
|
|
write_virtual_word(i->seg, i->rm_addr, &limit_16);
|
|
|
|
|
|
|
|
write_virtual_dword(i->seg, i->rm_addr+2, &base_32);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
BX_CPU_C::SIDT_Ms(BxInstruction_t *i)
|
|
|
|
{
|
|
|
|
#if BX_CPU_LEVEL < 2
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("SIDT_Ms: not supported on 8086!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
#else
|
|
|
|
Bit16u limit_16;
|
|
|
|
Bit32u base_32;
|
|
|
|
|
2001-05-30 22:56:02 +04:00
|
|
|
if (v8086_mode()) BX_PANIC(("protect_ctrl: v8086 mode unsupported"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* op1 is a register or memory reference */
|
|
|
|
if (i->mod == 0xc0) {
|
|
|
|
/* undefined opcode exception */
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("SIDT: use of register is undefined opcode."));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
limit_16 = BX_CPU_THIS_PTR idtr.limit;
|
|
|
|
base_32 = BX_CPU_THIS_PTR idtr.base;
|
|
|
|
|
|
|
|
#if BX_CPU_LEVEL == 2
|
|
|
|
base_32 |= 0xff000000;
|
|
|
|
#else /* 386+ */
|
|
|
|
/* ??? regardless of operand size, all 32bits of base are stored */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
write_virtual_word(i->seg, i->rm_addr, &limit_16);
|
|
|
|
|
|
|
|
write_virtual_dword(i->seg, i->rm_addr+2, &base_32);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
BX_CPU_C::LGDT_Ms(BxInstruction_t *i)
|
|
|
|
{
|
|
|
|
#if BX_CPU_LEVEL < 2
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("LGDT_Ms: not supported on 8086!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
#else
|
|
|
|
|
2001-05-30 22:56:02 +04:00
|
|
|
if (v8086_mode()) BX_PANIC(("protect_ctrl: v8086 mode unsupported"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
|
|
|
if (protected_mode() && (CPL!=0)) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("LGDT: protected mode: CPL!=0"));
|
2001-04-10 05:04:59 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* op1 is a register or memory reference */
|
|
|
|
if (i->mod == 0xc0) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("LGDT generating exception 6"));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if BX_CPU_LEVEL >= 3
|
|
|
|
if (i->os_32) {
|
|
|
|
Bit16u limit_16;
|
|
|
|
Bit32u base0_31;
|
|
|
|
|
|
|
|
read_virtual_word(i->seg, i->rm_addr, &limit_16);
|
|
|
|
|
|
|
|
read_virtual_dword(i->seg, i->rm_addr + 2, &base0_31);
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR gdtr.limit = limit_16;
|
|
|
|
BX_CPU_THIS_PTR gdtr.base = base0_31;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
Bit16u limit_16, base0_15;
|
|
|
|
Bit8u base16_23;
|
|
|
|
|
|
|
|
read_virtual_word(i->seg, i->rm_addr, &limit_16);
|
|
|
|
|
|
|
|
read_virtual_word(i->seg, i->rm_addr + 2, &base0_15);
|
|
|
|
|
|
|
|
read_virtual_byte(i->seg, i->rm_addr + 4, &base16_23);
|
|
|
|
|
|
|
|
/* ignore high 8 bits */
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR gdtr.limit = limit_16;
|
|
|
|
BX_CPU_THIS_PTR gdtr.base = (base16_23 << 16) | base0_15;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
BX_CPU_C::LIDT_Ms(BxInstruction_t *i)
|
|
|
|
{
|
|
|
|
#if BX_CPU_LEVEL < 2
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("LIDT_Ms: not supported on 8086!"));
|
2001-04-10 05:04:59 +04:00
|
|
|
#else
|
|
|
|
Bit16u limit_16;
|
|
|
|
Bit32u base_32;
|
|
|
|
|
|
|
|
|
2001-05-30 22:56:02 +04:00
|
|
|
if (v8086_mode()) BX_PANIC(("protect_ctrl: v8086 mode unsupported"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
|
|
|
if (protected_mode()) {
|
|
|
|
if (CPL != 0) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("LIDT(): CPL(%u) != 0", (unsigned) CPL));
|
2001-04-10 05:04:59 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* op1 is a register or memory reference */
|
|
|
|
if (i->mod == 0xc0) {
|
|
|
|
/* undefined opcode exception */
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("LIDT generating exception 6"));
|
2001-04-10 05:04:59 +04:00
|
|
|
UndefinedOpcode(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
read_virtual_word(i->seg, i->rm_addr, &limit_16);
|
|
|
|
|
|
|
|
read_virtual_dword(i->seg, i->rm_addr + 2, &base_32);
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR idtr.limit = limit_16;
|
|
|
|
|
|
|
|
#if BX_CPU_LEVEL >= 3
|
|
|
|
if (i->os_32)
|
|
|
|
BX_CPU_THIS_PTR idtr.base = base_32;
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
BX_CPU_THIS_PTR idtr.base = base_32 & 0x00ffffff; /* ignore upper 8 bits */
|
|
|
|
|
|
|
|
#endif
|
|
|
|
}
|