Fixed CALL/JMP far through call gate 64

Decode SWAPGS and RDTSCP instructions
Indent changes in fetchdecode
This commit is contained in:
Stanislav Shwartsman 2006-03-22 20:47:11 +00:00
parent 912b07fde8
commit f347ab97bf
11 changed files with 4646 additions and 4640 deletions

View File

@ -4,6 +4,7 @@ Changes after 2.2.6 release:
- Recognize #XF exception (19) when SSE is enabled
- Fixed bug in SYSRET instruction legacy mode
- Fixed bug in PSRAW/PSRAD MMX and SSE instructions
- Fixed bug in CALL/JMP far through call gate 64 in x86-64 mode
- Fixed bug in ENTER instruction in x86-64 mode (Stanislav Shwartsman)
- Fixes in Bochs debugger and disassembler
- Save and restore RIP/RSP only for FAULT-type exceptions, not for traps

View File

@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////
// $Id: call_far.cc,v 1.9 2006-03-06 22:02:51 sshwarts Exp $
// $Id: call_far.cc,v 1.10 2006-03-22 20:47:11 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -127,7 +127,7 @@ BX_CPU_C::call_protected(bxInstruction_c *i, Bit16u cs_raw, bx_address disp)
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc, 0);
}
else {
call_gate64(&gate_descriptor);
call_gate64(&gate_selector);
return;
}
}
@ -458,18 +458,21 @@ BX_CPU_C::call_protected(bxInstruction_c *i, Bit16u cs_raw, bx_address disp)
}
#if BX_SUPPORT_X86_64
void BX_CPP_AttrRegparmN(1)
BX_CPU_C::call_gate64(bx_descriptor_t *gate_descriptor)
void BX_CPP_AttrRegparmN(3)
BX_CPU_C::call_gate64(bx_selector_t *gate_selector)
{
bx_selector_t cs_selector;
Bit32u dword1, dword2, dword3;
bx_descriptor_t cs_descriptor;
bx_descriptor_t gate_descriptor;
// examine code segment selector in call gate descriptor
BX_DEBUG(("call_gate64: CALL 64bit call gate"));
Bit16u dest_selector = gate_descriptor->u.gate386.dest_selector;
fetch_raw_descriptor64(gate_selector, &dword1, &dword2, &dword3, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &gate_descriptor);
Bit16u dest_selector = gate_descriptor.u.gate386.dest_selector;
// selector must not be null else #GP(0)
if ( (dest_selector & 0xfffc) == 0 ) {
BX_ERROR(("call_gate64: selector in gate null"));
@ -479,10 +482,11 @@ BX_CPU_C::call_gate64(bx_descriptor_t *gate_descriptor)
parse_selector(dest_selector, &cs_selector);
// selector must be within its descriptor table limits,
// else #GP(code segment selector)
fetch_raw_descriptor64(&cs_selector, &dword1, &dword2, &dword3, BX_GP_EXCEPTION);
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &cs_descriptor);
Bit64u new_RIP = gate_descriptor->u.gate386.dest_offset;
// find the RIP in the gate_descriptor
Bit64u new_RIP = gate_descriptor.u.gate386.dest_offset;
new_RIP |= ((Bit64u)dword3 << 32);
// AR byte of selected descriptor must indicate code segment,

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: cpu.h,v 1.270 2006-03-16 20:24:09 sshwarts Exp $
// $Id: cpu.h,v 1.271 2006-03-22 20:47:11 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -2759,11 +2759,11 @@ public: // for now...
BX_SMF void jmp_call_gate16(bx_descriptor_t *gate_descriptor) BX_CPP_AttrRegparmN(1);
BX_SMF void jmp_call_gate32(bx_descriptor_t *gate_descriptor) BX_CPP_AttrRegparmN(1);
#if BX_SUPPORT_X86_64
BX_SMF void jmp_call_gate64(bx_descriptor_t *gate_descriptor) BX_CPP_AttrRegparmN(1);
BX_SMF void jmp_call_gate64(bx_selector_t *selector) BX_CPP_AttrRegparmN(1);
#endif
BX_SMF void call_protected(bxInstruction_c *, Bit16u cs, bx_address disp) BX_CPP_AttrRegparmN(3);
#if BX_SUPPORT_X86_64
BX_SMF void call_gate64(bx_descriptor_t *gate_descriptor) BX_CPP_AttrRegparmN(1);
BX_SMF void call_gate64(bx_selector_t *selector) BX_CPP_AttrRegparmN(1);
#endif
BX_SMF void return_protected(bxInstruction_c *, Bit16u pop_bytes) BX_CPP_AttrRegparmN(2);
BX_SMF void iret_protected(bxInstruction_c *) BX_CPP_AttrRegparmN(1);
@ -2809,13 +2809,13 @@ public: // for now...
BX_SMF void check_cs(bx_descriptor_t *descriptor, Bit16u cs_raw, Bit8u check_rpl, Bit8u check_cpl);
BX_SMF void load_cs(bx_selector_t *selector, bx_descriptor_t *descriptor, Bit8u cpl) BX_CPP_AttrRegparmN(3);
BX_SMF void load_ss(bx_selector_t *selector, bx_descriptor_t *descriptor, Bit8u cpl) BX_CPP_AttrRegparmN(3);
BX_SMF void fetch_raw_descriptor(bx_selector_t *selector,
BX_SMF void fetch_raw_descriptor(const bx_selector_t *selector,
Bit32u *dword1, Bit32u *dword2, unsigned exception) BX_CPP_AttrRegparmN(3);
BX_SMF bx_bool fetch_raw_descriptor2(bx_selector_t *selector,
BX_SMF bx_bool fetch_raw_descriptor2(const bx_selector_t *selector,
Bit32u *dword1, Bit32u *dword2) BX_CPP_AttrRegparmN(3);
BX_SMF void load_seg_reg(bx_segment_reg_t *seg, Bit16u new_value) BX_CPP_AttrRegparmN(2);
#if BX_SUPPORT_X86_64
BX_SMF void fetch_raw_descriptor64(bx_selector_t *selector,
BX_SMF void fetch_raw_descriptor64(const bx_selector_t *selector,
Bit32u *dword1, Bit32u *dword2, Bit32u *dword3, unsigned exception_no);
BX_SMF void loadSRegLMNominal(unsigned seg, unsigned selector,
bx_address base, unsigned dpl);
@ -3295,6 +3295,7 @@ IMPLEMENT_EFLAG_ACCESSOR (TF, 8)
#define BxPrefixSSE 0x0020 // Group encoding: 010
#define BxSplitMod11b 0x0030 // Group encoding: 011
#define BxFPGroup 0x0040 // Group encoding: 100
#define BxRMGroup 0x0050 // Group encoding: 101
#define BxPrefix 0x0080 // bit 7
#define BxAnother 0x0100 // bit 8

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: ctrl_xfer64.cc,v 1.44 2006-03-16 20:24:09 sshwarts Exp $
// $Id: ctrl_xfer64.cc,v 1.45 2006-03-22 20:47:11 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -42,7 +42,6 @@ void BX_CPU_C::RETnear64_Iw(bxInstruction_c *i)
BX_CPU_THIS_PTR show_flag |= Flag_ret;
#endif
Bit64u temp_RSP = RSP;
Bit16u imm16 = i->Iw();
pop_64(&return_RIP);
@ -66,8 +65,6 @@ void BX_CPU_C::RETnear64(bxInstruction_c *i)
BX_CPU_THIS_PTR show_flag |= Flag_ret;
#endif
Bit64u temp_RSP = RSP;
pop_64(&return_RIP);
if (! IsCanonical(return_RIP)) {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////
// $Id: jmp_far.cc,v 1.4 2006-03-06 22:03:00 sshwarts Exp $
// $Id: jmp_far.cc,v 1.5 2006-03-22 20:47:11 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -59,7 +59,7 @@ BX_CPU_C::jump_protected(bxInstruction_c *i, Bit16u cs_raw, bx_address disp)
/* examine AR byte of destination selector for legal values: */
parse_descriptor(dword1, dword2, &descriptor);
if ( descriptor.segment ) {
if (descriptor.segment) {
check_cs(&descriptor, cs_raw, BX_SELECTOR_RPL(cs_raw), CPL);
branch_far64(&selector, &descriptor, disp, CPL);
return;
@ -90,17 +90,17 @@ BX_CPU_C::jump_protected(bxInstruction_c *i, Bit16u cs_raw, bx_address disp)
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc, 0);
}
else {
jmp_call_gate64(&descriptor);
jmp_call_gate64(&selector);
return;
}
}
#endif
switch ( descriptor.type ) {
switch (descriptor.type) {
case BX_SYS_SEGMENT_AVAIL_286_TSS:
case BX_SYS_SEGMENT_AVAIL_386_TSS:
if ( descriptor.type==BX_SYS_SEGMENT_AVAIL_286_TSS )
if (descriptor.type==BX_SYS_SEGMENT_AVAIL_286_TSS)
BX_DEBUG(("jump to 286 TSS"));
else
BX_DEBUG(("jump to 386 TSS"));
@ -254,43 +254,55 @@ BX_CPU_C::jmp_call_gate32(bx_descriptor_t *gate_descriptor)
#if BX_SUPPORT_X86_64
void BX_CPP_AttrRegparmN(1)
BX_CPU_C::jmp_call_gate64(bx_descriptor_t *gate_descriptor)
BX_CPU_C::jmp_call_gate64(bx_selector_t *gate_selector)
{
bx_selector_t gate_cs_selector;
bx_descriptor_t gate_cs_descriptor;
bx_selector_t cs_selector;
Bit32u dword1, dword2, dword3;
Bit64u temp_RIP;
bx_descriptor_t cs_descriptor;
bx_descriptor_t gate_descriptor;
BX_DEBUG(("jump_protected: jump to CALL GATE 64"));
// examine selector to code segment given in call gate descriptor
// selector must not be null, else #GP(0)
Bit16u gate_cs_raw = gate_descriptor->u.gate386.dest_selector;
fetch_raw_descriptor64(gate_selector, &dword1, &dword2, &dword3, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &gate_descriptor);
if ((gate_cs_raw & 0xfffc) == 0) {
BX_ERROR(("jump_protected: CS selector null"));
Bit16u dest_selector = gate_descriptor.u.gate386.dest_selector;
// selector must not be null else #GP(0)
if ( (dest_selector & 0xfffc) == 0 ) {
BX_ERROR(("call_gate64: selector in gate null"));
exception(BX_GP_EXCEPTION, 0, 0);
}
parse_selector(gate_cs_raw, &gate_cs_selector);
// selector must be within its descriptor table limits else #GP(CS selector)
fetch_raw_descriptor64(&gate_cs_selector, &dword1, &dword2, &dword3, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &gate_cs_descriptor);
parse_selector(dest_selector, &cs_selector);
// selector must be within its descriptor table limits,
// else #GP(code segment selector)
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &cs_descriptor);
// find the RIP in the gate_descriptor
Bit64u new_RIP = gate_descriptor.u.gate386.dest_offset;
new_RIP |= ((Bit64u)dword3 << 32);
// AR byte of selected descriptor must indicate code segment,
// else #GP(code segment selector)
if (cs_descriptor.valid==0 || cs_descriptor.segment==0 ||
cs_descriptor.u.segment.executable==0)
{
BX_ERROR(("jump_protected: not code segment in call gate 64"));
exception(BX_GP_EXCEPTION, dest_selector & 0xfffc, 0);
}
// In long mode, only 64-bit call gates are allowed, and they must point
// to 64-bit code segments, else #GP(selector)
if (! IS_LONG64_SEGMENT(gate_cs_descriptor) || gate_cs_descriptor.u.segment.d_b)
if (! IS_LONG64_SEGMENT(cs_descriptor) || cs_descriptor.u.segment.d_b)
{
BX_ERROR(("jump_protected: not 64-bit code segment in call gate 64"));
exception(BX_GP_EXCEPTION, gate_cs_raw & 0xfffc, 0);
exception(BX_GP_EXCEPTION, dest_selector & 0xfffc, 0);
}
// check code-segment descriptor
check_cs(&gate_cs_descriptor, gate_cs_raw, 0, CPL);
temp_RIP = gate_descriptor->u.gate386.dest_offset;
temp_RIP |= ((Bit64u)dword3 << 32);
branch_far64(&gate_cs_selector, &gate_cs_descriptor, temp_RIP, CPL);
check_cs(&cs_descriptor, dest_selector, 0, CPL);
// and transfer the control
branch_far64(&cs_selector, &cs_descriptor, new_RIP, CPL);
}
#endif

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: paging.cc,v 1.67 2006-03-06 22:03:01 sshwarts Exp $
// $Id: paging.cc,v 1.68 2006-03-22 20:47:11 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -572,41 +572,7 @@ void BX_CPU_C::INVLPG(bxInstruction_c* i)
#if BX_CPU_LEVEL >= 4
invalidate_prefetch_q();
// Operand must not be a register
if (i->modC0()) {
#if BX_SUPPORT_X86_64
//
// Opcode 0F 01:
//
// ----------------------------------------------------
// MOD REG RM | non 64 bit mode | 64 bit mode
// ----------------------------------------------------
// MOD <> 11 7 --- | INVLPG | INVLPG
// MOD == 11 7 0 | #UD | SWAPGS
// MOD == 11 7 1 | #UD | RDTSCP
// MOD == 11 7 2-7 | #UD | #UD
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
if (i->nnn() == 7) {
switch(i->rm()) {
case 0:
BX_CPU_THIS_PTR SWAPGS(i);
return;
case 1:
BX_CPU_THIS_PTR RDTSCP(i);
return;
default:
BX_INFO(("INVLPG: 0F 01 /7 RM=%d opcode is undefined !", i->rm()));
UndefinedOpcode(i);
}
}
}
#endif
BX_INFO(("INVLPG: op is a register"));
UndefinedOpcode(i);
}

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: proc_ctrl.cc,v 1.141 2006-03-15 17:57:11 sshwarts Exp $
// $Id: proc_ctrl.cc,v 1.142 2006-03-22 20:47:11 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -737,7 +737,7 @@ void BX_CPU_C::MOV_CqRq(bxInstruction_c *i)
BX_CPU_THIS_PTR cr2 = val_64;
break;
case 3: // CR3
BX_INFO(("MOV_CqRq: write to CR3 of %08x:%08x",
BX_DEBUG(("MOV_CqRq: write to CR3 of %08x:%08x",
(Bit32u)(val_64 >> 32), (Bit32u)(val_64 & 0xFFFFFFFF)));
// Reserved bits take on value of MOV instruction
CR3_change(val_64);

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: segment_ctrl_pro.cc,v 1.54 2006-03-06 22:03:02 sshwarts Exp $
// $Id: segment_ctrl_pro.cc,v 1.55 2006-03-22 20:47:11 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -474,7 +474,7 @@ BX_CPU_C::load_ss(bx_selector_t *selector, bx_descriptor_t *descriptor, Bit8u cp
#if BX_CPU_LEVEL >= 2
void BX_CPP_AttrRegparmN(3)
BX_CPU_C::fetch_raw_descriptor(bx_selector_t *selector,
BX_CPU_C::fetch_raw_descriptor(const bx_selector_t *selector,
Bit32u *dword1, Bit32u *dword2, unsigned exception_no)
{
if (selector->ti == 0) { /* GDT */
@ -484,10 +484,8 @@ BX_CPU_C::fetch_raw_descriptor(bx_selector_t *selector,
BX_CPU_THIS_PTR gdtr.limit));
exception(exception_no, selector->value & 0xfffc, 0);
}
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);
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);
}
else { /* LDT */
if (BX_CPU_THIS_PTR ldtr.cache.valid==0) {
@ -500,23 +498,19 @@ BX_CPU_C::fetch_raw_descriptor(bx_selector_t *selector,
BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit));
exception(exception_no, selector->value & 0xfffc, 0);
}
access_linear(BX_CPU_THIS_PTR ldtr.cache.u.ldt.base + selector->index*8, 4, 0,
BX_READ, dword1);
access_linear(BX_CPU_THIS_PTR ldtr.cache.u.ldt.base + selector->index*8 + 4, 4, 0,
BX_READ, dword2);
access_linear(BX_CPU_THIS_PTR ldtr.cache.u.ldt.base + selector->index*8, 4, 0, BX_READ, dword1);
access_linear(BX_CPU_THIS_PTR ldtr.cache.u.ldt.base + selector->index*8+4, 4, 0, BX_READ, dword2);
}
}
bx_bool BX_CPP_AttrRegparmN(3)
BX_CPU_C::fetch_raw_descriptor2(bx_selector_t *selector, Bit32u *dword1, Bit32u *dword2)
BX_CPU_C::fetch_raw_descriptor2(const bx_selector_t *selector, Bit32u *dword1, Bit32u *dword2)
{
if (selector->ti == 0) { /* GDT */
if ((selector->index*8 + 7) > BX_CPU_THIS_PTR gdtr.limit)
return(0);
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);
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);
return(1);
}
else { /* LDT */
@ -526,18 +520,18 @@ BX_CPU_C::fetch_raw_descriptor2(bx_selector_t *selector, Bit32u *dword1, Bit32u
}
if ((selector->index*8 + 7) > BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit)
return(0);
access_linear(BX_CPU_THIS_PTR ldtr.cache.u.ldt.base + selector->index*8, 4, 0,
BX_READ, dword1);
access_linear(BX_CPU_THIS_PTR ldtr.cache.u.ldt.base + selector->index*8 + 4, 4, 0,
BX_READ, dword2);
access_linear(BX_CPU_THIS_PTR ldtr.cache.u.ldt.base + selector->index*8, 4, 0, BX_READ, dword1);
access_linear(BX_CPU_THIS_PTR ldtr.cache.u.ldt.base + selector->index*8+4, 4, 0, BX_READ, dword2);
return(1);
}
}
#if BX_SUPPORT_X86_64
void BX_CPU_C::fetch_raw_descriptor64(bx_selector_t *selector,
void BX_CPU_C::fetch_raw_descriptor64(const bx_selector_t *selector,
Bit32u *dword1, Bit32u *dword2, Bit32u *dword3, unsigned exception_no)
{
Bit32u dword4;
if (selector->ti == 0) { /* GDT */
if ((selector->index*8 + 15) > BX_CPU_THIS_PTR gdtr.limit) {
BX_ERROR(("fetch_raw_descriptor64: GDT: index (%x)%x > limit (%x)",
@ -545,12 +539,11 @@ void BX_CPU_C::fetch_raw_descriptor64(bx_selector_t *selector,
BX_CPU_THIS_PTR gdtr.limit));
exception(exception_no, selector->value & 0xfffc, 0);
}
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);
access_linear(BX_CPU_THIS_PTR gdtr.base + selector->index*8 + 8, 4, 0,
BX_READ, dword3);
bx_address base = BX_CPU_THIS_PTR gdtr.base;
access_linear(base + selector->index*8, 4, 0, BX_READ, dword1);
access_linear(base + selector->index*8 + 4, 4, 0, BX_READ, dword2);
access_linear(base + selector->index*8 + 8, 4, 0, BX_READ, dword3);
access_linear(base + selector->index*8 + 12, 4, 0, BX_READ, &dword4);
}
else { /* LDT */
if (BX_CPU_THIS_PTR ldtr.cache.valid==0) {
@ -563,12 +556,16 @@ void BX_CPU_C::fetch_raw_descriptor64(bx_selector_t *selector,
BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit));
exception(exception_no, selector->value & 0xfffc, 0);
}
access_linear(BX_CPU_THIS_PTR ldtr.cache.u.ldt.base + selector->index*8, 4, 0,
BX_READ, dword1);
access_linear(BX_CPU_THIS_PTR ldtr.cache.u.ldt.base + selector->index*8 + 4, 4, 0,
BX_READ, dword2);
access_linear(BX_CPU_THIS_PTR ldtr.cache.u.ldt.base + selector->index*8 + 8, 4, 0,
BX_READ, dword3);
bx_address base = BX_CPU_THIS_PTR ldtr.cache.u.ldt.base;
access_linear(base + selector->index*8, 4, 0, BX_READ, dword1);
access_linear(base + selector->index*8 + 4, 4, 0, BX_READ, dword2);
access_linear(base + selector->index*8 + 8, 4, 0, BX_READ, dword3);
access_linear(base + selector->index*8 + 12, 4, 0, BX_READ, &dword4);
}
if (dword4 != 0) {
BX_ERROR(("fetch_raw_descriptor64: extended attributes DWORD4 != 0"));
exception(BX_GP_EXCEPTION, selector->value & 0xfffc, 0);
}
}
#endif