2001-10-03 17:10:38 +04:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2009-04-05 23:09:44 +04:00
|
|
|
// $Id: protect_ctrl.cc,v 1.93 2009-04-05 19:09:44 sshwarts 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
|
2009-01-16 21:18:59 +03:00
|
|
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
|
2007-11-18 02:28:33 +03:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2001-04-10 05:04:59 +04:00
|
|
|
|
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"
|
2006-03-07 01:03:16 +03:00
|
|
|
#include "cpu.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
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ARPL_EwGw(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
Bit16u op2_16, op1_16;
|
|
|
|
|
2007-09-30 22:47:41 +04:00
|
|
|
if (real_mode() || v8086_mode()) {
|
2007-10-12 23:45:12 +04:00
|
|
|
BX_DEBUG(("ARPL: not recognized in real or virtual-8086 mode"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2007-09-30 22:47:41 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-09-30 22:47:41 +04:00
|
|
|
/* op1_16 is a register or memory reference */
|
|
|
|
if (i->modC0()) {
|
|
|
|
op1_16 = BX_READ_16BIT_REG(i->rm());
|
|
|
|
}
|
|
|
|
else {
|
2008-08-08 13:22:49 +04:00
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
2007-09-30 22:47:41 +04:00
|
|
|
/* pointer, segment address pair */
|
2008-08-08 13:22:49 +04:00
|
|
|
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
2007-09-30 22:47:41 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-09-30 22:47:41 +04:00
|
|
|
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->modC0()) {
|
|
|
|
BX_WRITE_16BIT_REG(i->rm(), op1_16);
|
2005-01-28 23:50:48 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
else {
|
2007-09-30 22:47:41 +04:00
|
|
|
write_RMW_virtual_word(op1_16);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2007-10-22 02:07:33 +04:00
|
|
|
assert_ZF();
|
2005-01-28 23:50:48 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
else {
|
2007-10-22 02:07:33 +04:00
|
|
|
clear_ZF();
|
2005-01-28 23:50:48 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LAR_GvEw(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
/* for 16 bit operand size mode */
|
|
|
|
Bit16u raw_selector;
|
|
|
|
bx_descriptor_t descriptor;
|
2003-10-05 00:22:24 +04:00
|
|
|
bx_selector_t selector;
|
2001-04-10 05:04:59 +04:00
|
|
|
Bit32u dword1, dword2;
|
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
if (real_mode() || v8086_mode()) {
|
2007-01-27 01:12:05 +03:00
|
|
|
BX_ERROR(("LAR: not recognized in real or virtual-8086 mode"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2003-10-05 00:22:24 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2002-09-20 07:52:59 +04:00
|
|
|
if (i->modC0()) {
|
2002-09-18 02:50:53 +04:00
|
|
|
raw_selector = BX_READ_16BIT_REG(i->rm());
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
else {
|
2008-08-08 13:22:49 +04:00
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
2001-04-10 05:04:59 +04:00
|
|
|
/* pointer, segment address pair */
|
2008-08-08 13:22:49 +04:00
|
|
|
raw_selector = read_virtual_word(i->seg(), eaddr);
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* if selector null, clear ZF and done */
|
2003-10-05 00:22:24 +04:00
|
|
|
if ((raw_selector & 0xfffc) == 0) {
|
2005-10-16 01:01:36 +04:00
|
|
|
clear_ZF();
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
parse_selector(raw_selector, &selector);
|
|
|
|
|
2008-05-27 01:46:39 +04:00
|
|
|
if (!fetch_raw_descriptor2(&selector, &dword1, &dword2)) {
|
|
|
|
BX_DEBUG(("LAR: failed to fetch descriptor"));
|
|
|
|
clear_ZF();
|
|
|
|
return;
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
parse_descriptor(dword1, dword2, &descriptor);
|
|
|
|
|
|
|
|
if (descriptor.valid==0) {
|
2008-05-27 01:46:39 +04:00
|
|
|
BX_DEBUG(("LAR: descriptor not valid"));
|
2005-10-16 01:01:36 +04:00
|
|
|
clear_ZF();
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* 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
|
|
|
|
*/
|
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
if (descriptor.segment) { /* normal segment */
|
2006-06-12 20:58:27 +04:00
|
|
|
if (IS_CODE_SEGMENT(descriptor.type) && IS_CODE_SEGMENT_CONFORMING(descriptor.type)) {
|
2001-04-10 05:04:59 +04:00
|
|
|
/* ignore DPL for conforming segments */
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
else {
|
2003-10-05 00:22:24 +04:00
|
|
|
if ((descriptor.dpl<CPL) || (descriptor.dpl<selector.rpl)) {
|
2005-10-16 01:01:36 +04:00
|
|
|
clear_ZF();
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2005-10-16 01:01:36 +04:00
|
|
|
assert_ZF();
|
2002-09-18 09:36:48 +04:00
|
|
|
if (i->os32L()) {
|
2001-04-10 05:04:59 +04:00
|
|
|
/* masked by 00FxFF00, where x is undefined */
|
2002-09-18 02:50:53 +04:00
|
|
|
BX_WRITE_32BIT_REGZ(i->nnn(), dword2 & 0x00ffff00);
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
else {
|
2002-09-18 02:50:53 +04:00
|
|
|
BX_WRITE_16BIT_REG(i->nnn(), dword2 & 0xff00);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
else { /* system or gate segment */
|
2003-10-05 00:22:24 +04:00
|
|
|
switch (descriptor.type) {
|
2005-02-27 20:41:45 +03:00
|
|
|
case BX_SYS_SEGMENT_AVAIL_286_TSS:
|
|
|
|
case BX_SYS_SEGMENT_BUSY_286_TSS:
|
|
|
|
case BX_286_CALL_GATE:
|
|
|
|
case BX_TASK_GATE:
|
2008-04-23 02:05:38 +04:00
|
|
|
if (long_mode()) {
|
|
|
|
BX_DEBUG(("LAR: descriptor type in not accepted in long mode"));
|
|
|
|
clear_ZF();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* fall through */
|
|
|
|
case BX_SYS_SEGMENT_LDT:
|
2001-04-10 05:04:59 +04:00
|
|
|
#if BX_CPU_LEVEL >= 3
|
2005-02-27 20:41:45 +03:00
|
|
|
case BX_SYS_SEGMENT_AVAIL_386_TSS:
|
|
|
|
case BX_SYS_SEGMENT_BUSY_386_TSS:
|
|
|
|
case BX_386_CALL_GATE:
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
default: /* rest not accepted types to LAR */
|
2008-04-23 02:05:38 +04:00
|
|
|
BX_DEBUG(("LAR: not accepted descriptor type"));
|
2005-10-16 01:01:36 +04:00
|
|
|
clear_ZF();
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
2005-02-27 20:41:45 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
if ((descriptor.dpl<CPL) || (descriptor.dpl<selector.rpl)) {
|
2005-10-16 01:01:36 +04:00
|
|
|
clear_ZF();
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
2005-02-27 20:41:45 +03:00
|
|
|
}
|
2005-10-16 01:01:36 +04:00
|
|
|
assert_ZF();
|
2002-09-18 09:36:48 +04:00
|
|
|
if (i->os32L()) {
|
2003-10-05 00:22:24 +04:00
|
|
|
/* masked by 00FxFF00, where x is undefined ? */
|
2002-09-18 02:50:53 +04:00
|
|
|
BX_WRITE_32BIT_REGZ(i->nnn(), dword2 & 0x00ffff00);
|
2005-02-27 20:41:45 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
else {
|
2002-09-18 02:50:53 +04:00
|
|
|
BX_WRITE_16BIT_REG(i->nnn(), dword2 & 0xff00);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2005-02-27 20:41:45 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LSL_GvEw(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
/* for 16 bit operand size mode */
|
|
|
|
Bit16u raw_selector;
|
|
|
|
Bit32u limit32;
|
2003-10-05 00:22:24 +04:00
|
|
|
bx_selector_t selector;
|
2001-04-10 05:04:59 +04:00
|
|
|
Bit32u dword1, dword2;
|
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
if (real_mode() || v8086_mode()) {
|
2007-01-27 01:12:05 +03:00
|
|
|
BX_ERROR(("LSL: not recognized in real or virtual-8086 mode"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2003-10-05 00:22:24 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2002-09-20 07:52:59 +04:00
|
|
|
if (i->modC0()) {
|
2002-09-18 02:50:53 +04:00
|
|
|
raw_selector = BX_READ_16BIT_REG(i->rm());
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
else {
|
2008-08-08 13:22:49 +04:00
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
2001-04-10 05:04:59 +04:00
|
|
|
/* pointer, segment address pair */
|
2008-08-08 13:22:49 +04:00
|
|
|
raw_selector = read_virtual_word(i->seg(), eaddr);
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* if selector null, clear ZF and done */
|
2003-10-05 00:22:24 +04:00
|
|
|
if ((raw_selector & 0xfffc) == 0) {
|
2005-10-16 01:01:36 +04:00
|
|
|
clear_ZF();
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
parse_selector(raw_selector, &selector);
|
|
|
|
|
2008-05-27 01:46:39 +04:00
|
|
|
if (!fetch_raw_descriptor2(&selector, &dword1, &dword2)) {
|
|
|
|
clear_ZF();
|
|
|
|
return;
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2008-05-25 19:53:29 +04:00
|
|
|
Bit32u descriptor_dpl = (dword2 >> 13) & 0x03;
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
if ((dword2 & 0x00001000) == 0) { // system segment
|
|
|
|
Bit32u type = (dword2 >> 8) & 0x0000000f;
|
2001-04-10 05:04:59 +04:00
|
|
|
switch (type) {
|
2005-02-27 20:41:45 +03:00
|
|
|
case BX_SYS_SEGMENT_AVAIL_286_TSS:
|
|
|
|
case BX_SYS_SEGMENT_BUSY_286_TSS:
|
2008-04-23 02:05:38 +04:00
|
|
|
if (long_mode()) {
|
|
|
|
clear_ZF();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* fall through */
|
2005-02-27 20:41:45 +03:00
|
|
|
case BX_SYS_SEGMENT_LDT:
|
|
|
|
case BX_SYS_SEGMENT_AVAIL_386_TSS:
|
|
|
|
case BX_SYS_SEGMENT_BUSY_386_TSS:
|
2003-10-05 00:22:24 +04:00
|
|
|
if ((descriptor_dpl<CPL) || (descriptor_dpl<selector.rpl)) {
|
2005-10-16 01:01:36 +04:00
|
|
|
clear_ZF();
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
2005-02-27 20:41:45 +03:00
|
|
|
}
|
2008-04-23 02:05:38 +04:00
|
|
|
limit32 = (dword1 & 0x0000ffff) | (dword2 & 0x000f0000);
|
|
|
|
if (dword2 & 0x00800000)
|
|
|
|
limit32 = (limit32 << 12) | 0x00000fff;
|
|
|
|
break;
|
2001-04-10 05:04:59 +04:00
|
|
|
default:
|
2005-10-16 01:01:36 +04:00
|
|
|
clear_ZF();
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
|
|
|
}
|
2005-02-27 20:41:45 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
else { // data & code segment
|
|
|
|
limit32 = (dword1 & 0x0000ffff) | (dword2 & 0x000f0000);
|
2003-10-05 00:22:24 +04:00
|
|
|
if (dword2 & 0x00800000)
|
2001-04-10 05:04:59 +04:00
|
|
|
limit32 = (limit32 << 12) | 0x00000fff;
|
2008-04-23 02:05:38 +04:00
|
|
|
if ((dword2 & 0x00000c00) != 0x00000c00) {
|
|
|
|
// non-conforming code segment
|
|
|
|
if ((descriptor_dpl<CPL) || (descriptor_dpl<selector.rpl)) {
|
|
|
|
clear_ZF();
|
|
|
|
return;
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2005-02-27 20:41:45 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* all checks pass, limit32 is now byte granular, write to op1 */
|
2005-10-16 01:01:36 +04:00
|
|
|
assert_ZF();
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-01-27 01:12:05 +03:00
|
|
|
if (i->os32L()) {
|
|
|
|
BX_WRITE_32BIT_REGZ(i->nnn(), limit32);
|
|
|
|
}
|
|
|
|
else {
|
2001-04-10 05:04:59 +04:00
|
|
|
// chop off upper 16 bits
|
2007-01-27 01:12:05 +03:00
|
|
|
BX_WRITE_16BIT_REG(i->nnn(), (Bit16u) limit32);
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SLDT_Ew(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2003-10-05 00:22:24 +04:00
|
|
|
if (real_mode() || v8086_mode()) {
|
2007-01-27 01:12:05 +03:00
|
|
|
BX_ERROR(("SLDT: not recognized in real or virtual-8086 mode"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2005-01-28 23:50:48 +03:00
|
|
|
}
|
2006-08-22 23:06:03 +04:00
|
|
|
|
|
|
|
Bit16u val16 = BX_CPU_THIS_PTR ldtr.selector.value;
|
|
|
|
if (i->modC0()) {
|
2007-01-27 01:12:05 +03:00
|
|
|
if (i->os32L()) {
|
|
|
|
BX_WRITE_32BIT_REGZ(i->rm(), val16);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BX_WRITE_16BIT_REG(i->rm(), val16);
|
|
|
|
}
|
2006-08-22 23:06:03 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
else {
|
2008-08-08 13:22:49 +04:00
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
2008-01-10 22:37:56 +03:00
|
|
|
/* pointer, segment address pair */
|
2008-08-08 13:22:49 +04:00
|
|
|
write_virtual_word(i->seg(), eaddr, val16);
|
2005-01-28 23:50:48 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::STR_Ew(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2003-10-05 00:22:24 +04:00
|
|
|
if (real_mode() || v8086_mode()) {
|
2007-01-27 01:12:05 +03:00
|
|
|
BX_ERROR(("STR: not recognized in real or virtual-8086 mode"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2003-10-05 00:22:24 +04:00
|
|
|
}
|
2006-08-22 23:06:03 +04:00
|
|
|
|
|
|
|
Bit16u val16 = BX_CPU_THIS_PTR tr.selector.value;
|
|
|
|
if (i->modC0()) {
|
2007-01-27 01:12:05 +03:00
|
|
|
if (i->os32L()) {
|
|
|
|
BX_WRITE_32BIT_REGZ(i->rm(), val16);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BX_WRITE_16BIT_REG(i->rm(), val16);
|
|
|
|
}
|
2006-08-22 23:06:03 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
else {
|
2008-08-08 13:22:49 +04:00
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
2008-01-10 22:37:56 +03:00
|
|
|
/* pointer, segment address pair */
|
2008-08-08 13:22:49 +04:00
|
|
|
write_virtual_word(i->seg(), eaddr, val16);
|
2005-01-28 23:50:48 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LLDT_Ew(bxInstruction_c *i)
|
2005-08-21 22:23:36 +04:00
|
|
|
{
|
2003-10-05 00:22:24 +04:00
|
|
|
/* protected mode */
|
|
|
|
bx_descriptor_t descriptor;
|
|
|
|
bx_selector_t selector;
|
|
|
|
Bit16u raw_selector;
|
|
|
|
Bit32u dword1, dword2;
|
2008-05-05 01:25:16 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
Bit32u dword3 = 0;
|
|
|
|
#endif
|
2006-08-22 23:06:03 +04:00
|
|
|
|
|
|
|
if (real_mode() || v8086_mode()) {
|
2007-01-29 00:27:31 +03:00
|
|
|
BX_ERROR(("LLDT: not recognized in real or virtual-8086 mode"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2006-08-22 23:06:03 +04:00
|
|
|
}
|
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
if (CPL != 0) {
|
2007-01-27 01:12:05 +03:00
|
|
|
BX_ERROR(("LLDT: The current priveledge level is not 0"));
|
2005-03-13 21:20:26 +03:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2003-10-05 00:22:24 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
if (i->modC0()) {
|
2005-03-13 21:20:26 +03:00
|
|
|
raw_selector = BX_READ_16BIT_REG(i->rm());
|
2003-10-05 00:22:24 +04:00
|
|
|
}
|
|
|
|
else {
|
2008-08-08 13:22:49 +04:00
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
2008-01-10 22:37:56 +03:00
|
|
|
/* pointer, segment address pair */
|
2008-08-08 13:22:49 +04:00
|
|
|
raw_selector = read_virtual_word(i->seg(), eaddr);
|
2003-10-05 00:22:24 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-01-25 22:09:41 +03:00
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
/* if selector is NULL, invalidate and done */
|
|
|
|
if ((raw_selector & 0xfffc) == 0) {
|
2005-03-13 21:20:26 +03:00
|
|
|
BX_CPU_THIS_PTR ldtr.selector.value = raw_selector;
|
|
|
|
BX_CPU_THIS_PTR ldtr.cache.valid = 0;
|
|
|
|
return;
|
2003-10-05 00:22:24 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
/* parse fields in selector */
|
|
|
|
parse_selector(raw_selector, &selector);
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
// #GP(selector) if the selector operand does not point into GDT
|
|
|
|
if (selector.ti != 0) {
|
2005-03-13 21:20:26 +03:00
|
|
|
BX_ERROR(("LLDT: selector.ti != 0"));
|
|
|
|
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc, 0);
|
2003-10-05 00:22:24 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2008-05-05 01:25:16 +04:00
|
|
|
/* fetch descriptor; call handles out of limits checks */
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
|
2008-05-25 19:53:29 +04:00
|
|
|
fetch_raw_descriptor_64(&selector, &dword1, &dword2, &dword3, BX_GP_EXCEPTION);
|
2008-05-05 01:25:16 +04:00
|
|
|
}
|
2008-05-25 19:53:29 +04:00
|
|
|
else
|
2008-05-05 01:25:16 +04:00
|
|
|
#endif
|
2008-05-25 19:53:29 +04:00
|
|
|
{
|
2008-05-05 01:25:16 +04:00
|
|
|
fetch_raw_descriptor(&selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
|
|
|
}
|
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
parse_descriptor(dword1, dword2, &descriptor);
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
/* if selector doesn't point to an LDT descriptor #GP(selector) */
|
|
|
|
if (descriptor.valid == 0 || descriptor.segment ||
|
2008-02-03 00:46:54 +03:00
|
|
|
descriptor.type != BX_SYS_SEGMENT_LDT)
|
2003-10-05 00:22:24 +04:00
|
|
|
{
|
2005-03-13 21:20:26 +03:00
|
|
|
BX_ERROR(("LLDT: doesn't point to an LDT descriptor!"));
|
|
|
|
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc, 0);
|
2003-10-05 00:22:24 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
/* #NP(selector) if LDT descriptor is not present */
|
2005-07-11 00:32:32 +04:00
|
|
|
if (! IS_PRESENT(descriptor)) {
|
2005-03-13 21:20:26 +03:00
|
|
|
BX_ERROR(("LLDT: LDT descriptor not present!"));
|
|
|
|
exception(BX_NP_EXCEPTION, raw_selector & 0xfffc, 0);
|
2003-10-05 00:22:24 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2008-04-17 02:08:46 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
2009-04-05 23:09:44 +04:00
|
|
|
descriptor.u.segment.base |= ((Bit64u)(dword3) << 32);
|
2008-05-05 01:25:16 +04:00
|
|
|
BX_DEBUG(("64 bit LDT base = 0x%08x%08x",
|
2009-04-05 23:09:44 +04:00
|
|
|
GET32H(descriptor.u.segment.base), GET32L(descriptor.u.segment.base)));
|
|
|
|
if (!IsCanonical(descriptor.u.segment.base)) {
|
2008-05-05 01:25:16 +04:00
|
|
|
BX_ERROR(("LLDT: non-canonical LDT descriptor base!"));
|
|
|
|
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc, 0);
|
2008-04-17 02:08:46 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
BX_CPU_THIS_PTR ldtr.selector = selector;
|
|
|
|
BX_CPU_THIS_PTR ldtr.cache = descriptor;
|
|
|
|
BX_CPU_THIS_PTR ldtr.cache.valid = 1;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LTR_Ew(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2003-10-05 00:22:24 +04:00
|
|
|
bx_descriptor_t descriptor;
|
|
|
|
bx_selector_t selector;
|
|
|
|
Bit16u raw_selector;
|
|
|
|
Bit32u dword1, dword2;
|
2008-05-05 01:25:16 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
Bit32u dword3 = 0;
|
|
|
|
#endif
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2006-08-22 23:06:03 +04:00
|
|
|
if (real_mode() || v8086_mode()) {
|
2007-01-27 01:12:05 +03:00
|
|
|
BX_ERROR(("LTR: not recognized in real or virtual-8086 mode"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2006-08-22 23:06:03 +04:00
|
|
|
}
|
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
if (CPL != 0) {
|
2005-06-22 22:13:45 +04:00
|
|
|
BX_ERROR(("LTR: The current priveledge level is not 0"));
|
2005-03-13 21:20:26 +03:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2003-10-05 00:22:24 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
if (i->modC0()) {
|
2005-03-13 21:20:26 +03:00
|
|
|
raw_selector = BX_READ_16BIT_REG(i->rm());
|
2003-10-05 00:22:24 +04:00
|
|
|
}
|
|
|
|
else {
|
2008-08-08 13:22:49 +04:00
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
2008-01-10 22:37:56 +03:00
|
|
|
/* pointer, segment address pair */
|
2008-08-08 13:22:49 +04:00
|
|
|
raw_selector = read_virtual_word(i->seg(), eaddr);
|
2003-10-05 00:22:24 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-11-18 21:24:46 +03:00
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
/* if selector is NULL, invalidate and done */
|
2005-10-02 19:26:51 +04:00
|
|
|
if ((raw_selector & BX_SELECTOR_RPL_MASK) == 0) {
|
2005-10-01 11:47:00 +04:00
|
|
|
BX_ERROR(("LTR: loading with NULL selector!"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2003-10-05 00:22:24 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
/* parse fields in selector, then check for null selector */
|
|
|
|
parse_selector(raw_selector, &selector);
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
if (selector.ti) {
|
2005-06-22 22:13:45 +04:00
|
|
|
BX_ERROR(("LTR: selector.ti != 0"));
|
|
|
|
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc, 0);
|
2003-10-05 00:22:24 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2008-05-05 01:25:16 +04:00
|
|
|
/* fetch descriptor; call handles out of limits checks */
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
|
2008-05-25 19:53:29 +04:00
|
|
|
fetch_raw_descriptor_64(&selector, &dword1, &dword2, &dword3, BX_GP_EXCEPTION);
|
2008-05-05 01:25:16 +04:00
|
|
|
}
|
2008-05-25 19:53:29 +04:00
|
|
|
else
|
2008-05-05 01:25:16 +04:00
|
|
|
#endif
|
2008-05-25 19:53:29 +04:00
|
|
|
{
|
2008-05-05 01:25:16 +04:00
|
|
|
fetch_raw_descriptor(&selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
|
|
|
}
|
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
parse_descriptor(dword1, dword2, &descriptor);
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
/* #GP(selector) if object is not a TSS or is already busy */
|
|
|
|
if (descriptor.valid==0 || descriptor.segment ||
|
2008-02-03 00:46:54 +03:00
|
|
|
(descriptor.type!=BX_SYS_SEGMENT_AVAIL_286_TSS &&
|
|
|
|
descriptor.type!=BX_SYS_SEGMENT_AVAIL_386_TSS))
|
2003-10-05 00:22:24 +04:00
|
|
|
{
|
2005-06-22 22:13:45 +04:00
|
|
|
BX_ERROR(("LTR: doesn't point to an available TSS descriptor!"));
|
|
|
|
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc, 0);
|
2003-10-05 00:22:24 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-09-25 20:11:32 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
if (long_mode() && descriptor.type!=BX_SYS_SEGMENT_AVAIL_386_TSS) {
|
|
|
|
BX_ERROR(("LTR: doesn't point to an available TSS386 descriptor in long mode!"));
|
|
|
|
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc, 0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
/* #NP(selector) if TSS descriptor is not present */
|
2005-07-11 00:32:32 +04:00
|
|
|
if (! IS_PRESENT(descriptor)) {
|
2008-01-29 09:23:49 +03:00
|
|
|
BX_ERROR(("LTR: TSS descriptor not present!"));
|
2005-06-22 22:13:45 +04:00
|
|
|
exception(BX_NP_EXCEPTION, raw_selector & 0xfffc, 0);
|
2003-10-05 00:22:24 +04:00
|
|
|
}
|
|
|
|
|
2008-04-17 02:08:46 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
2009-04-05 23:09:44 +04:00
|
|
|
descriptor.u.segment.base |= ((Bit64u)(dword3) << 32);
|
2008-05-05 01:25:16 +04:00
|
|
|
BX_DEBUG(("64 bit TSS base = 0x%08x%08x",
|
2009-04-05 23:09:44 +04:00
|
|
|
GET32H(descriptor.u.segment.base), GET32L(descriptor.u.segment.base)));
|
|
|
|
if (!IsCanonical(descriptor.u.segment.base)) {
|
2008-05-05 01:25:16 +04:00
|
|
|
BX_ERROR(("LTR: non-canonical TSS descriptor base!"));
|
|
|
|
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc, 0);
|
2008-04-17 02:08:46 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
BX_CPU_THIS_PTR tr.selector = selector;
|
|
|
|
BX_CPU_THIS_PTR tr.cache = descriptor;
|
|
|
|
BX_CPU_THIS_PTR tr.cache.valid = 1;
|
2008-02-03 00:46:54 +03:00
|
|
|
// tr.cache.type should not have busy bit, or it would not get
|
2003-10-05 00:22:24 +04:00
|
|
|
// through the conditions above.
|
|
|
|
BX_ASSERT((BX_CPU_THIS_PTR tr.cache.type & 2) == 0);
|
2008-04-16 20:44:06 +04:00
|
|
|
BX_CPU_THIS_PTR tr.cache.type |= 2; // mark as busy
|
2003-10-05 00:22:24 +04:00
|
|
|
|
|
|
|
/* mark as busy */
|
2008-01-20 20:46:02 +03:00
|
|
|
if (!(dword2 & 0x0200)) {
|
|
|
|
dword2 |= 0x0200; /* set busy bit */
|
2008-03-29 21:18:08 +03:00
|
|
|
access_write_linear(BX_CPU_THIS_PTR gdtr.base + selector.index*8 + 4, 4, 0, &dword2);
|
2008-01-20 20:46:02 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VERR_Ew(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
/* for 16 bit operand size mode */
|
|
|
|
Bit16u raw_selector;
|
|
|
|
bx_descriptor_t descriptor;
|
2004-10-16 23:34:17 +04:00
|
|
|
bx_selector_t selector;
|
2001-04-10 05:04:59 +04:00
|
|
|
Bit32u dword1, dword2;
|
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
if (real_mode() || v8086_mode()) {
|
2007-01-27 01:12:05 +03:00
|
|
|
BX_ERROR(("VERR: not recognized in real or virtual-8086 mode"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2003-10-05 00:22:24 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2002-09-20 07:52:59 +04:00
|
|
|
if (i->modC0()) {
|
2002-09-18 02:50:53 +04:00
|
|
|
raw_selector = BX_READ_16BIT_REG(i->rm());
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
else {
|
2008-08-08 13:22:49 +04:00
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
2001-04-10 05:04:59 +04:00
|
|
|
/* pointer, segment address pair */
|
2008-08-08 13:22:49 +04:00
|
|
|
raw_selector = read_virtual_word(i->seg(), eaddr);
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* if selector null, clear ZF and done */
|
2003-10-05 00:22:24 +04:00
|
|
|
if ((raw_selector & 0xfffc) == 0) {
|
2005-10-16 01:01:36 +04:00
|
|
|
BX_DEBUG(("VERR: null selector"));
|
|
|
|
clear_ZF();
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
if (!fetch_raw_descriptor2(&selector, &dword1, &dword2)) {
|
2001-04-10 05:04:59 +04:00
|
|
|
/* not within descriptor table */
|
2005-10-16 01:01:36 +04:00
|
|
|
BX_DEBUG(("VERR: not within descriptor table"));
|
|
|
|
clear_ZF();
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
parse_descriptor(dword1, dword2, &descriptor);
|
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
if (descriptor.segment==0) { /* system or gate descriptor */
|
2005-10-16 01:01:36 +04:00
|
|
|
BX_DEBUG(("VERR: system descriptor"));
|
|
|
|
clear_ZF(); /* inaccessible */
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
if (descriptor.valid==0) {
|
2005-10-16 01:01:36 +04:00
|
|
|
BX_DEBUG(("VERR: valid bit cleared"));
|
|
|
|
clear_ZF(); /* inaccessible */
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* normal data/code segment */
|
2006-06-12 20:58:27 +04:00
|
|
|
if (IS_CODE_SEGMENT(descriptor.type)) { /* code segment */
|
2001-04-10 05:04:59 +04:00
|
|
|
/* ignore DPL for readable conforming segments */
|
2006-06-12 20:58:27 +04:00
|
|
|
if (IS_CODE_SEGMENT_CONFORMING(descriptor.type) &&
|
|
|
|
IS_CODE_SEGMENT_READABLE(descriptor.type))
|
|
|
|
{
|
2005-10-16 01:01:36 +04:00
|
|
|
BX_DEBUG(("VERR: conforming code, OK"));
|
|
|
|
assert_ZF(); /* accessible */
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2006-06-12 20:58:27 +04:00
|
|
|
if (!IS_CODE_SEGMENT_READABLE(descriptor.type)) {
|
2005-10-16 01:01:36 +04:00
|
|
|
BX_DEBUG(("VERR: code not readable"));
|
2006-06-12 20:58:27 +04:00
|
|
|
clear_ZF(); /* inaccessible */
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
/* readable, non-conforming code segment */
|
2003-10-05 00:22:24 +04:00
|
|
|
if ((descriptor.dpl<CPL) || (descriptor.dpl<selector.rpl)) {
|
2005-10-16 01:01:36 +04:00
|
|
|
BX_DEBUG(("VERR: non-conforming code not withing priv level"));
|
2006-06-12 20:58:27 +04:00
|
|
|
clear_ZF(); /* inaccessible */
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2008-07-14 18:46:45 +04:00
|
|
|
else {
|
|
|
|
assert_ZF(); /* accessible */
|
|
|
|
}
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
else { /* data segment */
|
2003-10-05 00:22:24 +04:00
|
|
|
if ((descriptor.dpl<CPL) || (descriptor.dpl<selector.rpl)) {
|
2005-10-16 01:01:36 +04:00
|
|
|
BX_DEBUG(("VERR: data seg not withing priv level"));
|
|
|
|
clear_ZF(); /* not accessible */
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2008-07-14 18:46:45 +04:00
|
|
|
else {
|
|
|
|
assert_ZF(); /* accessible */
|
|
|
|
}
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VERW_Ew(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
/* for 16 bit operand size mode */
|
|
|
|
Bit16u raw_selector;
|
|
|
|
bx_descriptor_t descriptor;
|
2003-10-05 00:22:24 +04:00
|
|
|
bx_selector_t selector;
|
2001-04-10 05:04:59 +04:00
|
|
|
Bit32u dword1, dword2;
|
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
if (real_mode() || v8086_mode()) {
|
2007-01-27 01:12:05 +03:00
|
|
|
BX_ERROR(("VERW: not recognized in real or virtual-8086 mode"));
|
2008-07-13 19:35:10 +04:00
|
|
|
exception(BX_UD_EXCEPTION, 0, 0);
|
2003-10-05 00:22:24 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2002-09-20 07:52:59 +04:00
|
|
|
if (i->modC0()) {
|
2002-09-18 02:50:53 +04:00
|
|
|
raw_selector = BX_READ_16BIT_REG(i->rm());
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
else {
|
2008-08-08 13:22:49 +04:00
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
2001-04-10 05:04:59 +04:00
|
|
|
/* pointer, segment address pair */
|
2008-08-08 13:22:49 +04:00
|
|
|
raw_selector = read_virtual_word(i->seg(), eaddr);
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* if selector null, clear ZF and done */
|
2003-10-05 00:22:24 +04:00
|
|
|
if ((raw_selector & 0xfffc) == 0) {
|
2005-10-16 01:01:36 +04:00
|
|
|
BX_DEBUG(("VERW: null selector"));
|
|
|
|
clear_ZF();
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
if (!fetch_raw_descriptor2(&selector, &dword1, &dword2)) {
|
2001-04-10 05:04:59 +04:00
|
|
|
/* not within descriptor table */
|
2005-10-16 01:01:36 +04:00
|
|
|
BX_DEBUG(("VERW: not within descriptor table"));
|
|
|
|
clear_ZF();
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
2003-10-05 00:22:24 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
parse_descriptor(dword1, dword2, &descriptor);
|
|
|
|
|
|
|
|
/* rule out system segments & code segments */
|
2006-06-12 20:58:27 +04:00
|
|
|
if (descriptor.segment==0 || IS_CODE_SEGMENT(descriptor.type)) {
|
2005-10-16 01:01:36 +04:00
|
|
|
BX_DEBUG(("VERW: system seg or code"));
|
|
|
|
clear_ZF();
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
2003-10-05 00:22:24 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-10-05 00:22:24 +04:00
|
|
|
if (descriptor.valid==0) {
|
2005-10-16 01:01:36 +04:00
|
|
|
BX_DEBUG(("VERW: valid bit cleared"));
|
|
|
|
clear_ZF();
|
2001-04-10 05:04:59 +04:00
|
|
|
return;
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
/* data segment */
|
2006-06-12 20:58:27 +04:00
|
|
|
if (IS_DATA_SEGMENT_WRITEABLE(descriptor.type)) { /* writable */
|
2003-10-05 00:22:24 +04:00
|
|
|
if ((descriptor.dpl<CPL) || (descriptor.dpl<selector.rpl)) {
|
2005-10-16 01:01:36 +04:00
|
|
|
BX_DEBUG(("VERW: writable data seg not within priv level"));
|
|
|
|
clear_ZF(); /* not accessible */
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2008-07-14 18:46:45 +04:00
|
|
|
else {
|
|
|
|
assert_ZF(); /* accessible */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BX_DEBUG(("VERW: data seg not writable"));
|
|
|
|
clear_ZF(); /* not accessible */
|
2005-03-13 21:20:26 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SGDT_Ms(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2007-01-27 01:12:05 +03:00
|
|
|
Bit16u limit_16 = BX_CPU_THIS_PTR gdtr.limit;
|
2007-12-23 20:21:28 +03:00
|
|
|
Bit32u base_32 = (Bit32u) BX_CPU_THIS_PTR gdtr.base;
|
2002-09-14 01:08:54 +04:00
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
2008-01-10 22:37:56 +03:00
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
write_virtual_word_32(i->seg(), eaddr, limit_16);
|
|
|
|
write_virtual_dword_32(i->seg(), eaddr+2, base_32);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SIDT_Ms(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2007-01-27 01:12:05 +03:00
|
|
|
Bit16u limit_16 = BX_CPU_THIS_PTR idtr.limit;
|
2007-12-23 20:21:28 +03:00
|
|
|
Bit32u base_32 = (Bit32u) BX_CPU_THIS_PTR idtr.base;
|
2002-09-14 01:08:54 +04:00
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
2008-01-10 22:37:56 +03:00
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
write_virtual_word_32(i->seg(), eaddr, limit_16);
|
|
|
|
write_virtual_dword_32(i->seg(), eaddr+2, base_32);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LGDT_Ms(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2003-10-05 00:48:13 +04:00
|
|
|
if (v8086_mode()) {
|
2007-01-27 01:12:05 +03:00
|
|
|
BX_ERROR(("LGDT: not recognized in virtual-8086 mode"));
|
2003-10-05 00:48:13 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-10-05 00:48:13 +04:00
|
|
|
if (!real_mode() && CPL!=0) {
|
2007-01-27 01:12:05 +03:00
|
|
|
BX_ERROR(("LGDT: CPL!=0 in protected mode"));
|
2001-04-10 05:04:59 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
2003-10-05 00:48:13 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-01-27 01:12:05 +03:00
|
|
|
invalidate_prefetch_q();
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
2008-01-10 22:37:56 +03:00
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
Bit16u limit_16 = read_virtual_word_32(i->seg(), eaddr);
|
|
|
|
Bit32u base_32 = read_virtual_dword_32(i->seg(), eaddr + 2);
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-12-20 23:58:38 +03:00
|
|
|
if (i->os32L() == 0) base_32 &= 0x00ffffff; /* ignore upper 8 bits */
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-12-20 23:58:38 +03:00
|
|
|
BX_CPU_THIS_PTR gdtr.limit = limit_16;
|
|
|
|
BX_CPU_THIS_PTR gdtr.base = base_32;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LIDT_Ms(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2003-10-05 00:48:13 +04:00
|
|
|
if (v8086_mode()) {
|
2007-01-27 01:12:05 +03:00
|
|
|
BX_ERROR(("LIDT: not recognized in virtual-8086 mode"));
|
2003-10-05 00:48:13 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2003-10-05 00:48:13 +04:00
|
|
|
if (!real_mode() && CPL!=0) {
|
2005-10-16 01:01:36 +04:00
|
|
|
BX_ERROR(("LIDT: CPL!=0 in protected mode"));
|
2003-10-05 00:48:13 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-01-27 01:12:05 +03:00
|
|
|
invalidate_prefetch_q();
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
2008-01-10 22:37:56 +03:00
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
Bit32u base_32 = read_virtual_dword_32(i->seg(), eaddr + 2);
|
|
|
|
Bit16u limit_16 = read_virtual_word_32(i->seg(), eaddr);
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-12-20 23:58:38 +03:00
|
|
|
if (i->os32L() == 0) base_32 &= 0x00ffffff; /* ignore upper 8 bits */
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2007-12-20 23:58:38 +03:00
|
|
|
BX_CPU_THIS_PTR idtr.limit = limit_16;
|
|
|
|
BX_CPU_THIS_PTR idtr.base = base_32;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2005-08-21 22:23:36 +04:00
|
|
|
|
2007-01-27 01:12:05 +03:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SGDT64_Ms(bxInstruction_c *i)
|
2007-01-27 01:12:05 +03:00
|
|
|
{
|
|
|
|
Bit16u limit_16 = BX_CPU_THIS_PTR gdtr.limit;
|
|
|
|
Bit64u base_64 = BX_CPU_THIS_PTR gdtr.base;
|
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
2008-01-10 22:37:56 +03:00
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
write_virtual_word_64(i->seg(), eaddr, limit_16);
|
|
|
|
write_virtual_qword_64(i->seg(), eaddr+2, base_64);
|
2007-01-27 01:12:05 +03:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SIDT64_Ms(bxInstruction_c *i)
|
2007-01-27 01:12:05 +03:00
|
|
|
{
|
|
|
|
Bit16u limit_16 = BX_CPU_THIS_PTR idtr.limit;
|
|
|
|
Bit64u base_64 = BX_CPU_THIS_PTR idtr.base;
|
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
2008-01-10 22:37:56 +03:00
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
write_virtual_word_64(i->seg(), eaddr, limit_16);
|
|
|
|
write_virtual_qword_64(i->seg(), eaddr+2, base_64);
|
2007-01-27 01:12:05 +03:00
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LGDT64_Ms(bxInstruction_c *i)
|
2007-01-27 01:12:05 +03:00
|
|
|
{
|
|
|
|
if (CPL!=0) {
|
|
|
|
BX_ERROR(("LGDT64_Ms: CPL != 0 in long mode"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
2008-01-10 22:37:56 +03:00
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
Bit64u base_64 = read_virtual_qword_64(i->seg(), eaddr + 2);
|
2008-04-24 23:34:01 +04:00
|
|
|
if (! IsCanonical(base_64)) {
|
|
|
|
BX_ERROR(("LGDT64_Ms: loaded base64 address is not in canonical form!"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
2008-08-08 13:22:49 +04:00
|
|
|
Bit16u limit_16 = read_virtual_word_64(i->seg(), eaddr);
|
2007-01-27 01:12:05 +03:00
|
|
|
|
|
|
|
BX_CPU_THIS_PTR gdtr.limit = limit_16;
|
|
|
|
BX_CPU_THIS_PTR gdtr.base = base_64;
|
|
|
|
}
|
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LIDT64_Ms(bxInstruction_c *i)
|
2007-01-27 01:12:05 +03:00
|
|
|
{
|
|
|
|
if (CPL != 0) {
|
|
|
|
BX_ERROR(("LIDT64_Ms: CPL != 0 in long mode"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
2008-01-10 22:37:56 +03:00
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
Bit64u base_64 = read_virtual_qword_64(i->seg(), eaddr + 2);
|
2008-04-24 23:34:01 +04:00
|
|
|
if (! IsCanonical(base_64)) {
|
|
|
|
BX_ERROR(("LIDT64_Ms: loaded base64 address is not in canonical form!"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0, 0);
|
|
|
|
}
|
2008-08-08 13:22:49 +04:00
|
|
|
Bit16u limit_16 = read_virtual_word_64(i->seg(), eaddr);
|
2007-01-27 01:12:05 +03:00
|
|
|
|
|
|
|
BX_CPU_THIS_PTR idtr.limit = limit_16;
|
|
|
|
BX_CPU_THIS_PTR idtr.base = base_64;
|
|
|
|
}
|
|
|
|
|
2005-08-21 22:23:36 +04:00
|
|
|
#endif
|