From a0d90e9b39a6a2f53a38c459bf2632f59565eeb8 Mon Sep 17 00:00:00 2001 From: Peter Tattam Date: Wed, 25 Sep 2002 12:54:41 +0000 Subject: [PATCH] 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. --- bochs/cpu/cpu.h | 13 +- bochs/cpu/exception.cc | 261 ++++++++++++++++++++++++++++++++++++- bochs/cpu/fetchdecode.cc | 18 ++- bochs/cpu/fetchdecode64.cc | 14 +- 4 files changed, 296 insertions(+), 10 deletions(-) diff --git a/bochs/cpu/cpu.h b/bochs/cpu/cpu.h index 8278a162e..cb27d8a20 100644 --- a/bochs/cpu/cpu.h +++ b/bochs/cpu/cpu.h @@ -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 diff --git a/bochs/cpu/exception.cc b/bochs/cpu/exception.cc index adf66f15e..a8eb91de7 100644 --- a/bochs/cpu/exception.cc +++ b/bochs/cpu/exception.cc @@ -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 diff --git a/bochs/cpu/fetchdecode.cc b/bochs/cpu/fetchdecode.cc index c92e20322..f466d107d 100644 --- a/bochs/cpu/fetchdecode.cc +++ b/bochs/cpu/fetchdecode.cc @@ -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 }, diff --git a/bochs/cpu/fetchdecode64.cc b/bochs/cpu/fetchdecode64.cc index 0b7f3f930..e9e46676c 100644 --- a/bochs/cpu/fetchdecode64.cc +++ b/bochs/cpu/fetchdecode64.cc @@ -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 },