Implemented SYSCALL and SYSRET as part of x86-64 emulation.

Since the SYSCALL replaces the LOADALL instruction, it is incompatible with
earlier CPU types.

At moment, the SYSCALL is only enabled by x86-64 emulation, but the code
can be incorporated in IA32 only emulations.

Instructions added:

0F 05		SYSCALL		(replaces LOADALL)
0F 07		SYSRET		(new)

TODO:  restructure #if ... so that it can be used by non x86-64 emulations.
This commit is contained in:
Peter Tattam 2002-09-25 12:54:41 +00:00
parent 6ba1fd1b06
commit a0d90e9b39
4 changed files with 296 additions and 10 deletions

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: cpu.h,v 1.78 2002-09-24 18:33:37 kevinlawton Exp $
// $Id: cpu.h,v 1.79 2002-09-25 12:54:39 ptrumpet Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -166,6 +166,13 @@ typedef Bit32u bx_address;
#if BX_SUPPORT_X86_64
// access to 64 bit instruction pointer
#define RIP BX_CPU_THIS_PTR rip
// access to 64 bit MSR registers
#define MSR_STAR (BX_CPU_THIS_PTR msr.star)
#define MSR_LSTAR (BX_CPU_THIS_PTR msr.lstar)
#define MSR_CSTAR (BX_CPU_THIS_PTR msr.cstar)
#define MSR_FMASK (BX_CPU_THIS_PTR msr.fmask)
#endif
#if BX_SUPPORT_X86_64
@ -2226,6 +2233,10 @@ union {
BX_SMF void POP64_GS(bxInstruction_c *);
BX_SMF void PUSH64_SS(bxInstruction_c *);
BX_SMF void POP64_SS(bxInstruction_c *);
BX_SMF void SYSCALL(bxInstruction_c *i);
BX_SMF void SYSRET(bxInstruction_c *i);
#endif // #if BX_SUPPORT_X86_64
// mch added

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: exception.cc,v 1.19 2002-09-25 06:36:42 ptrumpet Exp $
// $Id: exception.cc,v 1.20 2002-09-25 12:54:40 ptrumpet Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -1059,3 +1059,262 @@ BX_CPU_C::shutdown_cpu(void)
BX_PANIC(("shutdown_cpu(): not finished"));
}
#if BX_SUPPORT_X86_64
void
BX_CPU_C::SYSCALL(bxInstruction_c *i)
{
/* pseudo code from AMD manual.
SYSCALL_START:
IF (MSR_EFER.SCE = 0) // Check if syscall/sysret are enabled.
EXCEPTION [#UD]
IF (LONG_MODE)
SYSCALL_LONG_MODE
ELSE // (LEGACY_MODE)
SYSCALL_LEGACY_MODE
SYSCALL_LONG_MODE:
RCX.q = next_RIP
R11.q = RFLAGS // with rf cleared
IF (64BIT_MODE)
temp_RIP.q = MSR_LSTAR
ELSE // (COMPATIBILITY_MODE)
temp_RIP.q = MSR_CSTAR
CS.sel = MSR_STAR.SYSCALL_CS AND 0xFFFC
CS.attr = 64-bit code,dpl0 // Always switch to 64-bit mode in long mode.
CS.base = 0x00000000
CS.limit = 0xFFFFFFFF
SS.sel = MSR_STAR.SYSCALL_CS + 8
SS.attr = 64-bit stack,dpl0
SS.base = 0x00000000
SS.limit = 0xFFFFFFFF
RFLAGS = RFLAGS AND ~MSR_SFMASK
RFLAGS.RF = 0
CPL = 0
RIP = temp_RIP
EXIT
SYSCALL_LEGACY_MODE:
RCX.d = next_RIP
temp_RIP.d = MSR_STAR.EIP
CS.sel = MSR_STAR.SYSCALL_CS AND 0xFFFC
CS.attr = 32-bit code,dpl0 // Always switch to 32-bit mode in legacy mode.
CS.base = 0x00000000
CS.limit = 0xFFFFFFFF
SS.sel = MSR_STAR.SYSCALL_CS + 8
SS.attr = 32-bit stack,dpl0
SS.base = 0x00000000
SS.limit = 0xFFFFFFFF
RFLAGS.VM,IF,RF=0
CPL = 0
RIP = temp_RIP
EXIT
*/
bx_address temp_RIP;
bx_descriptor_t cs_descriptor,ss_descriptor;
bx_selector_t cs_selector,ss_selector;
Bit32u dword1, dword2;
if (!BX_CPU_THIS_PTR msr.sce) {
exception(BX_GP_EXCEPTION, 0, 0);
}
invalidate_prefetch_q();
if (BX_CPU_THIS_PTR msr.lma) {
RCX = RIP;
#warning - PRT: SYSCALL -- do we reset RF/VM before saving to R11?
R11 = read_eflags();
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
temp_RIP = MSR_LSTAR;
}
else {
temp_RIP = MSR_CSTAR;
}
parse_selector((MSR_STAR >> 32) & 0xFFFC, &cs_selector);
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &cs_descriptor);
load_cs(&cs_selector, &cs_descriptor, 0);
parse_selector((MSR_STAR >> 32) + 8, &ss_selector);
fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &ss_descriptor);
load_ss(&ss_selector, &ss_descriptor, 0);
write_eflags(read_eflags() & MSR_FMASK,1,1,1,0);
BX_CPU_THIS_PTR clear_RF ();
RIP = temp_RIP;
}
else {
// legacy mode
ECX = EIP;
temp_RIP = MSR_STAR & 0xFFFFFFFF;
parse_selector((MSR_STAR >> 32) & 0xFFFC, &cs_selector);
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &cs_descriptor);
load_cs(&cs_selector, &cs_descriptor, 0);
parse_selector((MSR_STAR >> 32) + 8, &ss_selector);
fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &ss_descriptor);
load_ss(&ss_selector, &ss_descriptor, 0);
BX_CPU_THIS_PTR clear_VM ();
BX_CPU_THIS_PTR clear_IF ();
BX_CPU_THIS_PTR clear_RF ();
RIP = temp_RIP;
}
}
void
BX_CPU_C::SYSRET(bxInstruction_c *i)
{
/* from AMD manual
SYSRET_START:
IF (MSR_EFER.SCE = 0) // Check if syscall/sysret are enabled.
EXCEPTION [#UD]
IF ((!PROTECTED_MODE) || (CPL != 0))
EXCEPTION [#GP(0)] // SYSRET requires protected mode, cpl0
IF (64BIT_MODE)
SYSRET_64BIT_MODE
ELSE // (!64BIT_MODE)
SYSRET_NON_64BIT_MODE
SYSRET_64BIT_MODE:
IF (OPERAND_SIZE = 64) // Return to 64-bit mode.
{
CS.sel = (MSR_STAR.SYSRET_CS + 16) OR 3
CS.base = 0x00000000
CS.limit = 0xFFFFFFFF
CS.attr = 64-bit code,dpl3
temp_RIP.q = RCX
}
ELSE // Return to 32-bit compatibility mode.
{
CS.sel = MSR_STAR.SYSRET_CS OR 3
CS.base = 0x00000000
CS.limit = 0xFFFFFFFF
CS.attr = 32-bit code,dpl3
temp_RIP.d = RCX
}
SS.sel = MSR_STAR.SYSRET_CS + 8 // SS selector is changed,
// SS base, limit, attributes unchanged.
RFLAGS.q = R11 // RF=0,VM=0
CPL = 3
RIP = temp_RIP
EXIT
SYSRET_NON_64BIT_MODE:
CS.sel = MSR_STAR.SYSRET_CS OR 3 // Return to 32-bit legacy protected mode.
CS.base = 0x00000000
CS.limit = 0xFFFFFFFF
CS.attr = 32-bit code,dpl3
temp_RIP.d = RCX
SS.sel = MSR_STAR.SYSRET_CS + 8 // SS selector is changed.
// SS base, limit, attributes unchanged.
RFLAGS.IF = 1
CPL = 3
RIP = temp_RIP
EXIT
*/
bx_address temp_RIP;
bx_descriptor_t cs_descriptor,ss_descriptor;
bx_selector_t cs_selector,ss_selector;
Bit32u dword1, dword2;
if (!BX_CPU_THIS_PTR msr.sce) {
exception(BX_GP_EXCEPTION, 0, 0);
}
if(real_mode() || CPL != 0) {
exception(BX_GP_EXCEPTION, 0, 0);
}
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
if (i->os64L()) { // Return to 64-bit mode.
parse_selector(((MSR_STAR >> 48) + 16) | 3, &cs_selector);
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &cs_descriptor);
load_cs(&cs_selector, &cs_descriptor, 3);
temp_RIP = RCX;
}
else { // Return to 32-bit compatibility mode.
parse_selector((MSR_STAR >> 48) | 3, &cs_selector);
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &cs_descriptor);
load_cs(&cs_selector, &cs_descriptor, 3);
temp_RIP = ECX;
}
parse_selector((MSR_STAR >> 48) + 8, &ss_selector);
fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &ss_descriptor);
load_ss(&ss_selector, &ss_descriptor, 0);
// SS base, limit, attributes unchanged.
write_eflags(R11,1,1,1,1);
RIP = temp_RIP;
}
else { // (!64BIT_MODE)
parse_selector((MSR_STAR >> 48) + 16, &cs_selector);
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &cs_descriptor);
load_cs(&cs_selector, &cs_descriptor, 3);
temp_RIP = ECX;
parse_selector((MSR_STAR >> 48) + 8, &ss_selector);
fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
parse_descriptor(dword1, dword2, &ss_descriptor);
load_ss(&ss_selector, &ss_descriptor, 0);
BX_CPU_THIS_PTR assert_IF ();
RIP = temp_RIP;
}
}
#endif // BX_SUPPORT_X86_64

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: fetchdecode.cc,v 1.19 2002-09-22 18:22:24 kevinlawton Exp $
// $Id: fetchdecode.cc,v 1.20 2002-09-25 12:54:41 ptrumpet Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -646,9 +646,17 @@ static BxOpcodeInfo_t BxOpcodeInfo[512*2] = {
/* 0F 02 */ { BxAnother, &BX_CPU_C::LAR_GvEw },
/* 0F 03 */ { BxAnother, &BX_CPU_C::LSL_GvEw },
/* 0F 04 */ { 0, &BX_CPU_C::BxError },
#if BX_SUPPORT_X86_64
/* 0F 05 */ { 0, &BX_CPU_C::SYSCALL },
#else
/* 0F 05 */ { 0, &BX_CPU_C::LOADALL },
#endif
/* 0F 06 */ { 0, &BX_CPU_C::CLTS },
#if BX_SUPPORT_X86_64
/* 0F 07 */ { 0, &BX_CPU_C::SYSRET },
#else
/* 0F 07 */ { 0, &BX_CPU_C::BxError },
#endif
/* 0F 08 */ { 0, &BX_CPU_C::INVD },
/* 0F 09 */ { 0, &BX_CPU_C::WBINVD },
/* 0F 0A */ { 0, &BX_CPU_C::BxError },
@ -1167,9 +1175,17 @@ static BxOpcodeInfo_t BxOpcodeInfo[512*2] = {
/* 0F 02 */ { BxAnother, &BX_CPU_C::LAR_GvEw },
/* 0F 03 */ { BxAnother, &BX_CPU_C::LSL_GvEw },
/* 0F 04 */ { 0, &BX_CPU_C::BxError },
#if BX_SUPPORT_X86_64
/* 0F 05 */ { 0, &BX_CPU_C::SYSCALL },
#else
/* 0F 05 */ { 0, &BX_CPU_C::LOADALL },
#endif
/* 0F 06 */ { 0, &BX_CPU_C::CLTS },
#if BX_SUPPORT_X86_64
/* 0F 07 */ { 0, &BX_CPU_C::SYSRET },
#else
/* 0F 07 */ { 0, &BX_CPU_C::BxError },
#endif
/* 0F 08 */ { 0, &BX_CPU_C::INVD },
/* 0F 09 */ { 0, &BX_CPU_C::WBINVD },
/* 0F 0A */ { 0, &BX_CPU_C::BxError },

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////
// $Id: fetchdecode64.cc,v 1.12 2002-09-25 03:32:12 bdenney Exp $
// $Id: fetchdecode64.cc,v 1.13 2002-09-25 12:54:41 ptrumpet Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
@ -726,9 +726,9 @@ static BxOpcodeInfo_t BxOpcodeInfo64[512*3] = {
/* 0F 02 */ { BxAnother, &BX_CPU_C::LAR_GvEw },
/* 0F 03 */ { BxAnother, &BX_CPU_C::LSL_GvEw },
/* 0F 04 */ { 0, &BX_CPU_C::BxError },
/* 0F 05 */ { 0, &BX_CPU_C::LOADALL },
/* 0F 05 */ { 0, &BX_CPU_C::SYSCALL },
/* 0F 06 */ { 0, &BX_CPU_C::CLTS },
/* 0F 07 */ { 0, &BX_CPU_C::BxError },
/* 0F 07 */ { 0, &BX_CPU_C::SYSRET },
/* 0F 08 */ { 0, &BX_CPU_C::INVD },
/* 0F 09 */ { 0, &BX_CPU_C::WBINVD },
/* 0F 0A */ { 0, &BX_CPU_C::BxError },
@ -1242,9 +1242,9 @@ static BxOpcodeInfo_t BxOpcodeInfo64[512*3] = {
/* 0F 02 */ { BxAnother, &BX_CPU_C::LAR_GvEw },
/* 0F 03 */ { BxAnother, &BX_CPU_C::LSL_GvEw },
/* 0F 04 */ { 0, &BX_CPU_C::BxError },
/* 0F 05 */ { 0, &BX_CPU_C::LOADALL },
/* 0F 05 */ { 0, &BX_CPU_C::SYSCALL },
/* 0F 06 */ { 0, &BX_CPU_C::CLTS },
/* 0F 07 */ { 0, &BX_CPU_C::BxError },
/* 0F 07 */ { 0, &BX_CPU_C::SYSRET },
/* 0F 08 */ { 0, &BX_CPU_C::INVD },
/* 0F 09 */ { 0, &BX_CPU_C::WBINVD },
/* 0F 0A */ { 0, &BX_CPU_C::BxError },
@ -1757,9 +1757,9 @@ static BxOpcodeInfo_t BxOpcodeInfo64[512*3] = {
/* 0F 02 */ { BxAnother, &BX_CPU_C::LAR_GvEw },
/* 0F 03 */ { BxAnother, &BX_CPU_C::LSL_GvEw },
/* 0F 04 */ { 0, &BX_CPU_C::BxError },
/* 0F 05 */ { 0, &BX_CPU_C::LOADALL },
/* 0F 05 */ { 0, &BX_CPU_C::SYSCALL },
/* 0F 06 */ { 0, &BX_CPU_C::CLTS },
/* 0F 07 */ { 0, &BX_CPU_C::BxError },
/* 0F 07 */ { 0, &BX_CPU_C::SYSRET },
/* 0F 08 */ { 0, &BX_CPU_C::INVD },
/* 0F 09 */ { 0, &BX_CPU_C::WBINVD },
/* 0F 0A */ { 0, &BX_CPU_C::BxError },