2001-10-03 17:10:38 +04:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2011-02-25 00:54:04 +03:00
|
|
|
// $Id$
|
2001-10-03 17:10:38 +04:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
2019-05-25 21:32:17 +03:00
|
|
|
// Copyright (C) 2001-2019 The Bochs Project
|
2001-04-10 05:04:59 +04:00
|
|
|
//
|
|
|
|
// 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-10-11 22:12:00 +04: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
|
|
|
|
2020-05-19 19:01:23 +03:00
|
|
|
#include "wide_int.h"
|
2017-10-20 00:27:25 +03:00
|
|
|
#include "decoder/ia_opcodes.h"
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BxError(bxInstruction_c *i)
|
2016-06-13 00:23:48 +03:00
|
|
|
{
|
|
|
|
unsigned ia_opcode = i->getIaOpcode();
|
|
|
|
|
|
|
|
if (ia_opcode == BX_IA_ERROR) {
|
|
|
|
BX_DEBUG(("BxError: Encountered an unknown instruction (signalling #UD)"));
|
|
|
|
|
2021-01-02 16:43:10 +03:00
|
|
|
#if BX_DEBUGGER == 0 // with debugger it easy to see the #UD
|
2016-06-13 00:23:48 +03:00
|
|
|
if (LOG_THIS getonoff(LOGLEV_DEBUG))
|
|
|
|
debug_disasm_instruction(BX_CPU_THIS_PTR prev_rip);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BX_DEBUG(("%s: instruction not supported - signalling #UD", get_bx_opcode_name(ia_opcode)));
|
|
|
|
for (unsigned n=0; n<BX_ISA_EXTENSIONS_ARRAY_SIZE; n++)
|
|
|
|
BX_DEBUG(("ia_extensions_bitmask[%d]: %08x", n, BX_CPU_THIS_PTR ia_extensions_bitmask[n]));
|
|
|
|
}
|
|
|
|
|
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
|
|
|
|
|
|
|
BX_NEXT_TRACE(i); // keep compiler happy
|
|
|
|
}
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::UndefinedOpcode(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2010-09-25 01:15:16 +04:00
|
|
|
BX_DEBUG(("UndefinedOpcode: generate #UD exception"));
|
2010-03-14 18:51:27 +03:00
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_TRACE(i); // keep compiler happy
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NOP(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2003-11-14 00:17:31 +03:00
|
|
|
// No operation.
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2002-10-16 21:37:35 +04:00
|
|
|
}
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PAUSE(bxInstruction_c *i)
|
2009-01-27 23:29:05 +03:00
|
|
|
{
|
2009-01-31 13:43:24 +03:00
|
|
|
#if BX_SUPPORT_VMX
|
2011-08-10 00:50:51 +04:00
|
|
|
if (BX_CPU_THIS_PTR in_vmx_guest)
|
2012-07-26 20:03:26 +04:00
|
|
|
VMexit_PAUSE();
|
2009-01-31 13:43:24 +03:00
|
|
|
#endif
|
2011-07-07 00:01:18 +04:00
|
|
|
|
2011-12-25 23:35:29 +04:00
|
|
|
#if BX_SUPPORT_SVM
|
|
|
|
if (BX_CPU_THIS_PTR in_svm_guest) {
|
2013-01-09 01:03:22 +04:00
|
|
|
if (SVM_INTERCEPT(SVM_INTERCEPT0_PAUSE)) SvmInterceptPAUSE();
|
2011-12-25 23:35:29 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-07-07 00:01:18 +04:00
|
|
|
BX_NEXT_INSTR(i);
|
2009-01-27 23:29:05 +03:00
|
|
|
}
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PREFETCH(bxInstruction_c *i)
|
2002-10-16 21:37:35 +04:00
|
|
|
{
|
2008-01-10 22:37:56 +03:00
|
|
|
#if BX_INSTRUMENTATION
|
2015-05-17 00:06:59 +03:00
|
|
|
BX_INSTR_PREFETCH_HINT(BX_CPU_ID, i->src(), i->seg(), BX_CPU_RESOLVE_ADDR(i));
|
2008-01-10 22:37:56 +03:00
|
|
|
#endif
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CPUID(bxInstruction_c *i)
|
2011-07-28 20:17:42 +04:00
|
|
|
{
|
|
|
|
#if BX_CPU_LEVEL >= 4
|
|
|
|
|
|
|
|
#if BX_SUPPORT_VMX
|
|
|
|
if (BX_CPU_THIS_PTR in_vmx_guest) {
|
2012-07-26 20:03:26 +04:00
|
|
|
VMexit(VMX_VMEXIT_CPUID, 0);
|
2011-07-28 20:17:42 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-12-25 23:35:29 +04:00
|
|
|
#if BX_SUPPORT_SVM
|
|
|
|
if (BX_CPU_THIS_PTR in_svm_guest) {
|
2011-12-27 23:42:11 +04:00
|
|
|
if (SVM_INTERCEPT(SVM_INTERCEPT0_CPUID)) Svm_Vmexit(SVM_VMEXIT_CPUID);
|
2011-12-25 23:35:29 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-07-28 20:17:42 +04:00
|
|
|
struct cpuid_function_t leaf;
|
|
|
|
BX_CPU_THIS_PTR cpuid->get_cpuid_leaf(EAX, ECX, &leaf);
|
|
|
|
|
|
|
|
RAX = leaf.eax;
|
|
|
|
RBX = leaf.ebx;
|
|
|
|
RCX = leaf.ecx;
|
|
|
|
RDX = leaf.edx;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
|
|
|
}
|
|
|
|
|
2006-04-08 00:47:32 +04:00
|
|
|
//
|
2008-02-03 00:46:54 +03:00
|
|
|
// The shutdown state is very similar to the state following the exection
|
|
|
|
// if HLT instruction. In this mode the processor stops executing
|
|
|
|
// instructions until #NMI, #SMI, #RESET or #INIT is received. If
|
|
|
|
// shutdown occurs why in NMI interrupt handler or in SMM, a hardware
|
2006-04-08 00:47:32 +04:00
|
|
|
// reset must be used to restart the processor execution.
|
|
|
|
//
|
2006-04-05 21:31:35 +04:00
|
|
|
void BX_CPU_C::shutdown(void)
|
|
|
|
{
|
2011-12-27 23:42:11 +04:00
|
|
|
#if BX_SUPPORT_SVM
|
|
|
|
if (BX_CPU_THIS_PTR in_svm_guest) {
|
|
|
|
if (SVM_INTERCEPT(SVM_INTERCEPT0_SHUTDOWN)) Svm_Vmexit(SVM_VMEXIT_SHUTDOWN);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-04-09 19:43:15 +04:00
|
|
|
enter_sleep_state(BX_ACTIVITY_STATE_SHUTDOWN);
|
2006-04-08 00:47:32 +04:00
|
|
|
|
2013-04-09 19:43:15 +04:00
|
|
|
longjmp(BX_CPU_THIS_PTR jmp_buf_env, 1); // go back to main decode loop
|
|
|
|
}
|
|
|
|
|
|
|
|
void BX_CPU_C::enter_sleep_state(unsigned state)
|
|
|
|
{
|
|
|
|
switch(state) {
|
|
|
|
case BX_ACTIVITY_STATE_ACTIVE:
|
|
|
|
BX_ASSERT(0); // should not be used for entering active CPU state
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BX_ACTIVITY_STATE_HLT:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BX_ACTIVITY_STATE_WAIT_FOR_SIPI:
|
|
|
|
mask_event(BX_EVENT_INIT | BX_EVENT_SMI | BX_EVENT_NMI); // FIXME: all events should be masked
|
|
|
|
// fall through - mask interrupts as well
|
|
|
|
|
|
|
|
case BX_ACTIVITY_STATE_SHUTDOWN:
|
|
|
|
BX_CPU_THIS_PTR clear_IF(); // masking interrupts
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BX_ACTIVITY_STATE_MWAIT:
|
|
|
|
case BX_ACTIVITY_STATE_MWAIT_IF:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
BX_PANIC(("enter_sleep_state: unknown state %d", state));
|
|
|
|
}
|
2006-04-08 00:47:32 +04:00
|
|
|
|
|
|
|
// artificial trap bit, why use another variable.
|
2013-04-09 19:43:15 +04:00
|
|
|
BX_CPU_THIS_PTR activity_state = state;
|
2006-04-08 00:47:32 +04:00
|
|
|
BX_CPU_THIS_PTR async_event = 1; // so processor knows to check
|
2013-04-09 19:43:15 +04:00
|
|
|
// Execution completes. The processor will remain in a sleep
|
|
|
|
// state until one of the wakeup conditions is met.
|
2006-04-08 00:47:32 +04:00
|
|
|
|
|
|
|
BX_INSTR_HLT(BX_CPU_ID);
|
|
|
|
|
2008-04-16 01:29:18 +04:00
|
|
|
#if BX_DEBUGGER
|
|
|
|
bx_dbg_halt(BX_CPU_ID);
|
|
|
|
#endif
|
|
|
|
|
2008-02-03 00:46:54 +03:00
|
|
|
#if BX_USE_IDLE_HACK
|
2007-10-11 22:12:00 +04:00
|
|
|
bx_gui->sim_is_idle();
|
|
|
|
#endif
|
2006-04-05 21:31:35 +04:00
|
|
|
}
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::HLT(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2011-08-24 01:25:34 +04:00
|
|
|
// CPL is always 0 in real mode
|
|
|
|
if (/* !real_mode() && */ CPL!=0) {
|
2007-04-26 00:14:15 +04:00
|
|
|
BX_DEBUG(("HLT: %s priveledge check failed, CPL=%d, generate #GP(0)",
|
2006-08-11 21:23:36 +04:00
|
|
|
cpu_mode_string(BX_CPU_THIS_PTR cpu_mode), CPL));
|
2010-03-14 18:51:27 +03:00
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2006-04-08 00:47:32 +04:00
|
|
|
if (! BX_CPU_THIS_PTR get_IF()) {
|
2005-11-04 18:15:02 +03:00
|
|
|
BX_INFO(("WARNING: HLT instruction with IF=0!"));
|
2003-11-14 00:17:31 +03:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2009-01-31 13:43:24 +03:00
|
|
|
#if BX_SUPPORT_VMX
|
2012-01-18 01:50:15 +04:00
|
|
|
if (BX_CPU_THIS_PTR in_vmx_guest) {
|
|
|
|
if (VMEXIT(VMX_VM_EXEC_CTRL2_HLT_VMEXIT)) {
|
2012-07-26 20:03:26 +04:00
|
|
|
VMexit(VMX_VMEXIT_HLT, 0);
|
2012-01-18 01:50:15 +04:00
|
|
|
}
|
|
|
|
}
|
2009-01-31 13:43:24 +03:00
|
|
|
#endif
|
|
|
|
|
2011-12-25 23:35:29 +04:00
|
|
|
#if BX_SUPPORT_SVM
|
|
|
|
if (BX_CPU_THIS_PTR in_svm_guest) {
|
2011-12-27 23:42:11 +04:00
|
|
|
if (SVM_INTERCEPT(SVM_INTERCEPT0_HLT)) Svm_Vmexit(SVM_VMEXIT_HLT);
|
2011-12-25 23:35:29 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
// stops instruction execution and places the processor in a
|
2013-04-09 19:43:15 +04:00
|
|
|
// HALT state. An enabled interrupt, NMI, or reset will resume
|
|
|
|
// execution. If interrupt (including NMI) is used to resume
|
2001-04-10 05:04:59 +04:00
|
|
|
// execution after HLT, the saved CS:eIP points to instruction
|
|
|
|
// following HLT.
|
2013-04-09 19:43:15 +04:00
|
|
|
enter_sleep_state(BX_ACTIVITY_STATE_HLT);
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_TRACE(i);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2009-01-23 12:26:24 +03:00
|
|
|
/* 0F 08 */
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INVD(bxInstruction_c *i)
|
2009-01-23 12:26:24 +03:00
|
|
|
{
|
2011-08-24 01:25:34 +04:00
|
|
|
// CPL is always 0 in real mode
|
|
|
|
if (/* !real_mode() && */ CPL!=0) {
|
2013-12-03 00:06:59 +04:00
|
|
|
BX_ERROR(("%s: priveledge check failed, generate #GP(0)", i->getIaOpcodeNameShort()));
|
2010-03-14 18:51:27 +03:00
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
2009-01-23 12:26:24 +03:00
|
|
|
}
|
|
|
|
|
2009-01-31 13:43:24 +03:00
|
|
|
#if BX_SUPPORT_VMX
|
|
|
|
if (BX_CPU_THIS_PTR in_vmx_guest) {
|
2012-07-26 20:03:26 +04:00
|
|
|
VMexit(VMX_VMEXIT_INVD, 0);
|
2009-01-31 13:43:24 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-12-25 23:35:29 +04:00
|
|
|
#if BX_SUPPORT_SVM
|
|
|
|
if (BX_CPU_THIS_PTR in_svm_guest) {
|
2011-12-27 23:42:11 +04:00
|
|
|
if (SVM_INTERCEPT(SVM_INTERCEPT0_INVD)) Svm_Vmexit(SVM_VMEXIT_INVD);
|
2011-12-25 23:35:29 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-01-23 12:26:24 +03:00
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
|
|
|
BX_DEBUG(("INVD: Flush internal caches !"));
|
|
|
|
BX_INSTR_CACHE_CNTRL(BX_CPU_ID, BX_INSTR_INVD);
|
|
|
|
|
|
|
|
flushICaches();
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_TRACE(i);
|
2009-01-23 12:26:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 0F 09 */
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::WBINVD(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
2011-08-24 01:25:34 +04:00
|
|
|
// CPL is always 0 in real mode
|
|
|
|
if (/* !real_mode() && */ CPL!=0) {
|
2013-12-03 00:06:59 +04:00
|
|
|
BX_ERROR(("%s: priveledge check failed, generate #GP(0)", i->getIaOpcodeNameShort()));
|
2010-03-14 18:51:27 +03:00
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
2005-02-03 21:25:10 +03:00
|
|
|
}
|
2005-10-18 22:07:52 +04:00
|
|
|
|
2011-09-26 23:36:20 +04:00
|
|
|
#if BX_SUPPORT_VMX
|
2012-01-18 01:50:15 +04:00
|
|
|
if (BX_CPU_THIS_PTR in_vmx_guest) {
|
|
|
|
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_WBINVD_VMEXIT)) {
|
2012-07-26 20:03:26 +04:00
|
|
|
VMexit(VMX_VMEXIT_WBINVD, 0);
|
2012-01-18 01:50:15 +04:00
|
|
|
}
|
|
|
|
}
|
2010-03-15 18:48:01 +03:00
|
|
|
#endif
|
|
|
|
|
2011-12-27 00:51:57 +04:00
|
|
|
#if BX_SUPPORT_SVM
|
|
|
|
if (BX_CPU_THIS_PTR in_svm_guest) {
|
2011-12-27 23:42:11 +04:00
|
|
|
if (SVM_INTERCEPT(SVM_INTERCEPT1_WBINVD)) Svm_Vmexit(SVM_VMEXIT_WBINVD);
|
2011-12-27 00:51:57 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-09-21 12:55:10 +04:00
|
|
|
//invalidate_prefetch_q();
|
2007-12-14 23:41:09 +03:00
|
|
|
|
2012-09-21 12:55:10 +04:00
|
|
|
BX_DEBUG(("WBINVD: WB-Invalidate internal caches !"));
|
2009-01-23 12:26:24 +03:00
|
|
|
BX_INSTR_CACHE_CNTRL(BX_CPU_ID, BX_INSTR_WBINVD);
|
2007-12-14 23:41:09 +03:00
|
|
|
|
2012-09-21 12:55:10 +04:00
|
|
|
//flushICaches();
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_TRACE(i);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CLFLUSH(bxInstruction_c *i)
|
2007-01-29 00:27:31 +03:00
|
|
|
{
|
2015-05-17 00:06:59 +03:00
|
|
|
bx_address eaddr = BX_CPU_RESOLVE_ADDR(i);
|
2017-03-28 21:52:53 +03:00
|
|
|
bx_address laddr;
|
2008-09-09 00:47:33 +04:00
|
|
|
|
2017-03-28 21:52:53 +03:00
|
|
|
// CLFLUSH performs all the segmentation and paging checks that a 1-byte read would perform,
|
|
|
|
// except that it also allows references to execute-only segments.
|
2008-05-27 01:46:39 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
2017-03-28 21:52:53 +03:00
|
|
|
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64)
|
|
|
|
laddr = get_laddr64(i->seg(), eaddr);
|
|
|
|
else
|
2010-03-19 20:00:05 +03:00
|
|
|
#endif
|
2017-03-28 21:52:53 +03:00
|
|
|
laddr = agen_read_execute32(i->seg(), (Bit32u)eaddr, 1);
|
2008-01-17 01:56:17 +03:00
|
|
|
|
2017-03-28 21:52:53 +03:00
|
|
|
tickle_read_linear(i->seg(), laddr);
|
2008-01-17 01:56:17 +03:00
|
|
|
|
2017-03-28 21:52:53 +03:00
|
|
|
BX_INSTR_CLFLUSH(BX_CPU_ID, laddr, BX_CPU_THIS_PTR address_xlation.paddress1);
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2007-01-29 00:27:31 +03:00
|
|
|
}
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CLZERO(bxInstruction_c *i)
|
2017-03-25 23:12:31 +03:00
|
|
|
{
|
2018-08-26 21:11:10 +03:00
|
|
|
#if BX_CPU_LEVEL >= 6
|
2017-03-25 23:12:31 +03:00
|
|
|
bx_address eaddr = RAX & ~BX_CONST64(CACHE_LINE_SIZE-1) & i->asize_mask();
|
|
|
|
|
2018-04-04 22:31:56 +03:00
|
|
|
BxPackedZmmRegister zmmzero; // zmm is always made available even if EVEX is not compiled in
|
2017-03-25 23:12:31 +03:00
|
|
|
zmmzero.clear();
|
|
|
|
for (unsigned n=0; n<CACHE_LINE_SIZE; n += 64) {
|
|
|
|
write_virtual_zmmword(i->seg(), eaddr+n, &zmmzero);
|
|
|
|
}
|
2018-08-26 21:11:10 +03:00
|
|
|
#endif
|
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2017-03-25 23:12:31 +03:00
|
|
|
}
|
|
|
|
|
2006-04-05 21:31:35 +04:00
|
|
|
void BX_CPU_C::handleCpuModeChange(void)
|
|
|
|
{
|
2008-02-01 16:25:23 +03:00
|
|
|
unsigned mode = BX_CPU_THIS_PTR cpu_mode;
|
|
|
|
|
2006-04-05 21:31:35 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
2008-04-01 00:56:27 +04:00
|
|
|
if (BX_CPU_THIS_PTR efer.get_LMA()) {
|
2007-07-09 19:16:14 +04:00
|
|
|
if (! BX_CPU_THIS_PTR cr0.get_PE()) {
|
2006-04-05 21:31:35 +04:00
|
|
|
BX_PANIC(("change_cpu_mode: EFER.LMA is set when CR0.PE=0 !"));
|
|
|
|
}
|
|
|
|
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.l) {
|
|
|
|
BX_CPU_THIS_PTR cpu_mode = BX_MODE_LONG_64;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BX_CPU_THIS_PTR cpu_mode = BX_MODE_LONG_COMPAT;
|
2008-05-12 00:46:11 +04:00
|
|
|
// clear upper part of RIP/RSP when leaving 64-bit long mode
|
|
|
|
BX_CLEAR_64BIT_HIGH(BX_64BIT_REG_RIP);
|
|
|
|
BX_CLEAR_64BIT_HIGH(BX_64BIT_REG_RSP);
|
2006-04-05 21:31:35 +04:00
|
|
|
}
|
2012-03-27 19:21:40 +04:00
|
|
|
|
|
|
|
// switching between compatibility and long64 mode also affect SS.BASE
|
|
|
|
// which is always zero in long64 mode
|
|
|
|
invalidate_stack_cache();
|
2006-04-05 21:31:35 +04:00
|
|
|
}
|
2008-02-03 00:46:54 +03:00
|
|
|
else
|
2006-04-05 21:31:35 +04:00
|
|
|
#endif
|
|
|
|
{
|
2007-07-09 19:16:14 +04:00
|
|
|
if (BX_CPU_THIS_PTR cr0.get_PE()) {
|
2008-06-16 00:41:34 +04:00
|
|
|
if (BX_CPU_THIS_PTR get_VM()) {
|
2006-04-05 21:31:35 +04:00
|
|
|
BX_CPU_THIS_PTR cpu_mode = BX_MODE_IA32_V8086;
|
2012-01-02 00:26:23 +04:00
|
|
|
CPL = 3;
|
2008-06-16 00:41:34 +04:00
|
|
|
}
|
2008-02-01 16:25:23 +03:00
|
|
|
else
|
2006-04-05 21:31:35 +04:00
|
|
|
BX_CPU_THIS_PTR cpu_mode = BX_MODE_IA32_PROTECTED;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BX_CPU_THIS_PTR cpu_mode = BX_MODE_IA32_REAL;
|
2009-01-10 12:36:44 +03:00
|
|
|
|
|
|
|
// CS segment in real mode always allows full access
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = 1; /* data/code segment */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
|
|
|
|
2012-01-02 00:26:23 +04:00
|
|
|
CPL = 0;
|
2006-04-05 21:31:35 +04:00
|
|
|
}
|
|
|
|
}
|
2008-02-01 16:25:23 +03:00
|
|
|
|
2009-03-11 01:28:08 +03:00
|
|
|
updateFetchModeMask();
|
|
|
|
|
2011-03-19 23:09:34 +03:00
|
|
|
#if BX_CPU_LEVEL >= 6
|
|
|
|
#if BX_SUPPORT_AVX
|
2012-05-20 00:36:40 +04:00
|
|
|
handleAvxModeChange(); /* protected mode reloaded */
|
2011-03-19 23:09:34 +03:00
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2016-03-20 00:15:56 +03:00
|
|
|
// re-initialize protection keys
|
|
|
|
#if BX_SUPPORT_PKEYS
|
2020-05-29 15:35:30 +03:00
|
|
|
set_PKeys(BX_CPU_THIS_PTR pkru, BX_CPU_THIS_PTR pkrs);
|
2016-03-20 00:15:56 +03:00
|
|
|
#endif
|
|
|
|
|
2008-04-07 23:59:53 +04:00
|
|
|
if (mode != BX_CPU_THIS_PTR cpu_mode) {
|
2008-02-01 16:25:23 +03:00
|
|
|
BX_DEBUG(("%s activated", cpu_mode_string(BX_CPU_THIS_PTR cpu_mode)));
|
2008-04-07 23:59:53 +04:00
|
|
|
#if BX_DEBUGGER
|
|
|
|
if (BX_CPU_THIS_PTR mode_break) {
|
|
|
|
BX_CPU_THIS_PTR stop_reason = STOP_MODE_BREAK_POINT;
|
|
|
|
bx_debug_break(); // trap into debugger
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
2006-04-05 21:31:35 +04:00
|
|
|
}
|
|
|
|
|
2012-03-25 23:07:17 +04:00
|
|
|
#if BX_CPU_LEVEL >= 4
|
2007-11-21 00:22:03 +03:00
|
|
|
void BX_CPU_C::handleAlignmentCheck(void)
|
|
|
|
{
|
|
|
|
if (CPL == 3 && BX_CPU_THIS_PTR cr0.get_AM() && BX_CPU_THIS_PTR get_AC()) {
|
2012-03-25 23:07:17 +04:00
|
|
|
#if BX_SUPPORT_ALIGNMENT_CHECK == 0
|
2012-03-26 23:33:38 +04:00
|
|
|
BX_PANIC(("WARNING: Alignment check (#AC exception) was not compiled in !"));
|
2012-03-25 23:07:17 +04:00
|
|
|
#else
|
|
|
|
BX_CPU_THIS_PTR alignment_check_mask = 0xF;
|
|
|
|
#endif
|
2007-11-21 00:22:03 +03:00
|
|
|
}
|
2012-03-25 23:07:17 +04:00
|
|
|
#if BX_SUPPORT_ALIGNMENT_CHECK
|
2007-11-21 00:22:03 +03:00
|
|
|
else {
|
2012-03-25 23:07:17 +04:00
|
|
|
BX_CPU_THIS_PTR alignment_check_mask = 0;
|
2007-11-21 00:22:03 +03:00
|
|
|
}
|
2012-03-25 23:07:17 +04:00
|
|
|
#endif
|
2007-11-21 00:22:03 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-12-19 10:06:40 +03:00
|
|
|
#if BX_CPU_LEVEL >= 6
|
|
|
|
void BX_CPU_C::handleSseModeChange(void)
|
|
|
|
{
|
2010-12-23 00:16:02 +03:00
|
|
|
if(BX_CPU_THIS_PTR cr0.get_TS()) {
|
2010-12-19 10:06:40 +03:00
|
|
|
BX_CPU_THIS_PTR sse_ok = 0;
|
2010-12-23 00:16:02 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if(BX_CPU_THIS_PTR cr0.get_EM() || !BX_CPU_THIS_PTR cr4.get_OSFXSR())
|
|
|
|
BX_CPU_THIS_PTR sse_ok = 0;
|
|
|
|
else
|
|
|
|
BX_CPU_THIS_PTR sse_ok = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
updateFetchModeMask(); /* SSE_OK changed */
|
2010-12-19 10:06:40 +03:00
|
|
|
}
|
2010-12-23 00:16:02 +03:00
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BxNoSSE(bxInstruction_c *i)
|
2010-12-23 00:16:02 +03:00
|
|
|
{
|
|
|
|
if(BX_CPU_THIS_PTR cr0.get_EM() || !BX_CPU_THIS_PTR cr4.get_OSFXSR())
|
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
|
|
|
|
|
|
|
if(BX_CPU_THIS_PTR cr0.get_TS())
|
|
|
|
exception(BX_NM_EXCEPTION, 0);
|
2011-03-19 23:09:34 +03:00
|
|
|
|
|
|
|
BX_ASSERT(0);
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_TRACE(i); // keep compiler happy
|
2011-03-19 23:09:34 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#if BX_SUPPORT_AVX
|
|
|
|
void BX_CPU_C::handleAvxModeChange(void)
|
|
|
|
{
|
|
|
|
if(BX_CPU_THIS_PTR cr0.get_TS()) {
|
|
|
|
BX_CPU_THIS_PTR avx_ok = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (! protected_mode() || ! BX_CPU_THIS_PTR cr4.get_OSXSAVE() ||
|
2013-08-29 23:43:15 +04:00
|
|
|
(~BX_CPU_THIS_PTR xcr0.val32 & (BX_XCR0_SSE_MASK | BX_XCR0_YMM_MASK)) != 0) {
|
2013-10-08 22:31:18 +04:00
|
|
|
BX_CPU_THIS_PTR avx_ok = 0;
|
2013-08-29 23:43:15 +04:00
|
|
|
}
|
|
|
|
else {
|
2011-03-19 23:09:34 +03:00
|
|
|
BX_CPU_THIS_PTR avx_ok = 1;
|
2013-08-29 23:43:15 +04:00
|
|
|
|
|
|
|
#if BX_SUPPORT_EVEX
|
2013-10-08 22:31:18 +04:00
|
|
|
if ((~BX_CPU_THIS_PTR xcr0.val32 & BX_XCR0_OPMASK_MASK) != 0) {
|
|
|
|
BX_CPU_THIS_PTR opmask_ok = BX_CPU_THIS_PTR evex_ok = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BX_CPU_THIS_PTR opmask_ok = 1;
|
|
|
|
|
|
|
|
if ((~BX_CPU_THIS_PTR xcr0.val32 & (BX_XCR0_ZMM_HI256_MASK | BX_XCR0_HI_ZMM_MASK)) != 0)
|
|
|
|
BX_CPU_THIS_PTR evex_ok = 0;
|
|
|
|
else
|
|
|
|
BX_CPU_THIS_PTR evex_ok = 1;
|
|
|
|
}
|
2013-08-29 23:43:15 +04:00
|
|
|
#endif
|
|
|
|
}
|
2011-03-19 23:09:34 +03:00
|
|
|
}
|
|
|
|
|
2013-08-29 23:43:15 +04:00
|
|
|
#if BX_SUPPORT_EVEX
|
|
|
|
if (! BX_CPU_THIS_PTR avx_ok)
|
2013-10-08 22:31:18 +04:00
|
|
|
BX_CPU_THIS_PTR opmask_ok = BX_CPU_THIS_PTR evex_ok = 0;
|
2013-08-29 23:43:15 +04:00
|
|
|
#endif
|
|
|
|
|
2011-03-19 23:09:34 +03:00
|
|
|
updateFetchModeMask(); /* AVX_OK changed */
|
|
|
|
}
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BxNoAVX(bxInstruction_c *i)
|
2011-03-19 23:09:34 +03:00
|
|
|
{
|
|
|
|
if (! protected_mode() || ! BX_CPU_THIS_PTR cr4.get_OSXSAVE())
|
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
|
|
|
|
2013-07-26 16:50:56 +04:00
|
|
|
if (~BX_CPU_THIS_PTR xcr0.val32 & (BX_XCR0_SSE_MASK | BX_XCR0_YMM_MASK))
|
2011-03-19 23:09:34 +03:00
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
|
|
|
|
|
|
|
if(BX_CPU_THIS_PTR cr0.get_TS())
|
|
|
|
exception(BX_NM_EXCEPTION, 0);
|
|
|
|
|
|
|
|
BX_ASSERT(0);
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_TRACE(i); // keep compiler happy
|
2010-12-23 00:16:02 +03:00
|
|
|
}
|
2010-12-19 10:06:40 +03:00
|
|
|
#endif
|
|
|
|
|
2013-08-29 23:43:15 +04:00
|
|
|
#if BX_SUPPORT_EVEX
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BxNoOpMask(bxInstruction_c *i)
|
2013-10-08 22:31:18 +04:00
|
|
|
{
|
|
|
|
if (! protected_mode() || ! BX_CPU_THIS_PTR cr4.get_OSXSAVE())
|
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
|
|
|
|
|
|
|
if (~BX_CPU_THIS_PTR xcr0.val32 & (BX_XCR0_SSE_MASK | BX_XCR0_YMM_MASK | BX_XCR0_OPMASK_MASK))
|
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
|
|
|
|
|
|
|
if(BX_CPU_THIS_PTR cr0.get_TS())
|
|
|
|
exception(BX_NM_EXCEPTION, 0);
|
|
|
|
|
|
|
|
BX_ASSERT(0);
|
|
|
|
|
|
|
|
BX_NEXT_TRACE(i); // keep compiler happy
|
|
|
|
}
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BxNoEVEX(bxInstruction_c *i)
|
2013-08-29 23:43:15 +04:00
|
|
|
{
|
|
|
|
if (! protected_mode() || ! BX_CPU_THIS_PTR cr4.get_OSXSAVE())
|
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
|
|
|
|
|
|
|
if (~BX_CPU_THIS_PTR xcr0.val32 & (BX_XCR0_SSE_MASK | BX_XCR0_YMM_MASK | BX_XCR0_OPMASK_MASK | BX_XCR0_ZMM_HI256_MASK | BX_XCR0_HI_ZMM_MASK))
|
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
|
|
|
|
|
|
|
if(BX_CPU_THIS_PTR cr0.get_TS())
|
|
|
|
exception(BX_NM_EXCEPTION, 0);
|
|
|
|
|
|
|
|
BX_ASSERT(0);
|
|
|
|
|
|
|
|
BX_NEXT_TRACE(i); // keep compiler happy
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-03-19 23:09:34 +03:00
|
|
|
#endif
|
|
|
|
|
2012-03-25 15:54:32 +04:00
|
|
|
void BX_CPU_C::handleCpuContextChange(void)
|
|
|
|
{
|
|
|
|
TLB_flush();
|
|
|
|
|
|
|
|
invalidate_prefetch_q();
|
|
|
|
invalidate_stack_cache();
|
2012-10-04 00:24:29 +04:00
|
|
|
|
|
|
|
handleInterruptMaskChange();
|
|
|
|
|
2012-03-25 23:07:17 +04:00
|
|
|
#if BX_CPU_LEVEL >= 4
|
2012-03-25 15:54:32 +04:00
|
|
|
handleAlignmentCheck();
|
|
|
|
#endif
|
2012-10-04 00:24:29 +04:00
|
|
|
|
2012-03-25 15:54:32 +04:00
|
|
|
handleCpuModeChange();
|
2012-10-04 00:24:29 +04:00
|
|
|
|
2012-03-26 23:05:58 +04:00
|
|
|
#if BX_CPU_LEVEL >= 6
|
2012-03-25 15:54:32 +04:00
|
|
|
handleSseModeChange();
|
|
|
|
#if BX_SUPPORT_AVX
|
|
|
|
handleAvxModeChange();
|
|
|
|
#endif
|
2012-03-26 23:05:58 +04:00
|
|
|
#endif
|
2012-03-25 15:54:32 +04:00
|
|
|
}
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RDPMC(bxInstruction_c *i)
|
2003-10-24 22:34:16 +04:00
|
|
|
{
|
2010-02-26 14:44:50 +03:00
|
|
|
#if BX_CPU_LEVEL >= 5
|
2014-10-15 19:28:13 +04:00
|
|
|
// in real mode CPL=0
|
|
|
|
if (! BX_CPU_THIS_PTR cr4.get_PCE() && CPL != 0 /* && protected_mode() */) {
|
2013-12-03 00:06:59 +04:00
|
|
|
BX_ERROR(("%s: not allowed to use instruction !", i->getIaOpcodeNameShort()));
|
2011-12-26 20:33:13 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
|
|
|
}
|
2009-01-31 13:43:24 +03:00
|
|
|
|
|
|
|
#if BX_SUPPORT_VMX
|
2012-01-18 01:50:15 +04:00
|
|
|
if (BX_CPU_THIS_PTR in_vmx_guest) {
|
|
|
|
if (VMEXIT(VMX_VM_EXEC_CTRL2_RDPMC_VMEXIT)) {
|
2012-07-26 20:03:26 +04:00
|
|
|
VMexit(VMX_VMEXIT_RDPMC, 0);
|
2012-01-18 01:50:15 +04:00
|
|
|
}
|
|
|
|
}
|
2009-01-31 13:43:24 +03:00
|
|
|
#endif
|
|
|
|
|
2011-12-25 23:35:29 +04:00
|
|
|
#if BX_SUPPORT_SVM
|
2011-12-26 20:33:13 +04:00
|
|
|
if (BX_CPU_THIS_PTR in_svm_guest) {
|
2011-12-27 23:42:11 +04:00
|
|
|
if (SVM_INTERCEPT(SVM_INTERCEPT0_RDPMC)) Svm_Vmexit(SVM_VMEXIT_RDPMC);
|
2011-12-26 20:33:13 +04:00
|
|
|
}
|
2011-12-25 23:35:29 +04:00
|
|
|
#endif
|
|
|
|
|
2011-12-26 20:33:13 +04:00
|
|
|
/* According to manual, Pentium 4 has 18 counters,
|
|
|
|
* previous versions have two. And the P4 also can do
|
|
|
|
* short read-out (EDX always 0). Otherwise it is
|
|
|
|
* limited to 40 bits.
|
|
|
|
*/
|
2004-05-11 01:05:51 +04:00
|
|
|
|
2011-12-26 20:33:13 +04:00
|
|
|
if (BX_CPUID_SUPPORT_ISA_EXTENSION(BX_ISA_SSE2)) { // Pentium 4 processor (see cpuid.cc)
|
|
|
|
if ((ECX & 0x7fffffff) >= 18)
|
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if ((ECX & 0xffffffff) >= 2)
|
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
|
|
|
}
|
2010-02-26 01:04:31 +03:00
|
|
|
|
2011-12-26 20:33:13 +04:00
|
|
|
// Most counters are for hardware specific details, which
|
|
|
|
// we anyhow do not emulate (like pipeline stalls etc)
|
2004-05-11 01:05:51 +04:00
|
|
|
|
2011-12-26 20:33:13 +04:00
|
|
|
// Could be interesting to count number of memory reads,
|
|
|
|
// writes. Misaligned etc... But to monitor bochs, this
|
|
|
|
// is easier done from the host.
|
2004-05-11 01:05:51 +04:00
|
|
|
|
2011-12-26 20:33:13 +04:00
|
|
|
RAX = 0;
|
|
|
|
RDX = 0; // if P4 and ECX & 0x10000000, then always 0 (short read 32 bits)
|
2004-05-11 01:05:51 +04:00
|
|
|
|
2011-12-26 20:33:13 +04:00
|
|
|
BX_ERROR(("RDPMC: Performance Counters Support not implemented yet"));
|
2003-10-24 22:34:16 +04:00
|
|
|
#endif
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2006-01-21 15:06:03 +03:00
|
|
|
#if BX_CPU_LEVEL >= 5
|
2020-05-17 21:39:52 +03:00
|
|
|
|
2009-01-19 20:43:54 +03:00
|
|
|
Bit64u BX_CPU_C::get_TSC(void)
|
2006-01-21 15:06:03 +03:00
|
|
|
{
|
2020-05-21 22:58:16 +03:00
|
|
|
Bit64u tsc = bx_pc_system.time_ticks() + BX_CPU_THIS_PTR tsc_adjust;
|
|
|
|
return tsc;
|
|
|
|
}
|
|
|
|
|
2011-12-25 23:53:23 +04:00
|
|
|
#if BX_SUPPORT_VMX || BX_SUPPORT_SVM
|
2020-05-21 22:58:16 +03:00
|
|
|
Bit64u BX_CPU_C::get_TSC_VMXAdjust(Bit64u tsc)
|
|
|
|
{
|
2015-09-30 21:44:01 +03:00
|
|
|
#if BX_SUPPORT_VMX
|
|
|
|
if (BX_CPU_THIS_PTR in_vmx_guest) {
|
2020-05-17 21:39:52 +03:00
|
|
|
if (VMEXIT(VMX_VM_EXEC_CTRL2_TSC_OFFSET) && SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_TSC_SCALING)) {
|
|
|
|
Bit128u product_128;
|
|
|
|
long_mul(&product_128,tsc,BX_CPU_THIS_PTR vmcs.tsc_multiplier);
|
|
|
|
tsc = (product_128.lo >> 48) | (product_128.hi << 16); // tsc = (uint64) (long128(tsc_value * tsc_multiplier) >> 48);
|
|
|
|
}
|
2015-09-30 21:44:01 +03:00
|
|
|
}
|
|
|
|
#endif
|
2020-05-21 22:58:16 +03:00
|
|
|
tsc += BX_CPU_THIS_PTR tsc_offset; // BX_CPU_THIS_PTR tsc_offset = 0 if not in VMX or SVM guest
|
2009-01-19 20:43:54 +03:00
|
|
|
return tsc;
|
2006-01-21 15:06:03 +03:00
|
|
|
}
|
2020-05-21 22:58:16 +03:00
|
|
|
#endif
|
2006-01-21 15:06:03 +03:00
|
|
|
|
2008-04-18 22:32:40 +04:00
|
|
|
void BX_CPU_C::set_TSC(Bit64u newval)
|
2006-01-21 15:06:03 +03:00
|
|
|
{
|
2020-05-21 22:58:16 +03:00
|
|
|
// compute the correct setting of tsc_adjust so that a get_TSC()
|
2006-01-21 15:06:03 +03:00
|
|
|
// will return newval
|
2020-05-21 22:58:16 +03:00
|
|
|
BX_CPU_THIS_PTR tsc_adjust = newval - bx_pc_system.time_ticks();
|
2006-01-21 15:06:03 +03:00
|
|
|
|
|
|
|
// verify
|
2009-01-19 20:43:54 +03:00
|
|
|
BX_ASSERT(get_TSC() == newval);
|
2006-01-21 15:06:03 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RDTSC(bxInstruction_c *i)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
#if BX_CPU_LEVEL >= 5
|
2011-12-25 23:35:29 +04:00
|
|
|
if (BX_CPU_THIS_PTR cr4.get_TSD() && CPL != 0) {
|
2013-12-03 00:06:59 +04:00
|
|
|
BX_ERROR(("%s: not allowed to use instruction !", i->getIaOpcodeNameShort()));
|
2011-12-25 23:35:29 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
|
|
|
}
|
2009-01-31 13:43:24 +03:00
|
|
|
|
|
|
|
#if BX_SUPPORT_VMX
|
2012-01-18 01:50:15 +04:00
|
|
|
if (BX_CPU_THIS_PTR in_vmx_guest) {
|
|
|
|
if (VMEXIT(VMX_VM_EXEC_CTRL2_RDTSC_VMEXIT)) {
|
2012-07-26 20:03:26 +04:00
|
|
|
VMexit(VMX_VMEXIT_RDTSC, 0);
|
2012-01-18 01:50:15 +04:00
|
|
|
}
|
|
|
|
}
|
2009-01-31 13:43:24 +03:00
|
|
|
#endif
|
|
|
|
|
2011-12-25 23:35:29 +04:00
|
|
|
#if BX_SUPPORT_SVM
|
|
|
|
if (BX_CPU_THIS_PTR in_svm_guest)
|
2011-12-27 23:42:11 +04:00
|
|
|
if (SVM_INTERCEPT(SVM_INTERCEPT0_RDTSC)) Svm_Vmexit(SVM_VMEXIT_RDTSC);
|
2011-12-25 23:35:29 +04:00
|
|
|
#endif
|
2009-01-31 13:43:24 +03:00
|
|
|
|
2011-12-25 23:35:29 +04:00
|
|
|
// return ticks
|
|
|
|
Bit64u ticks = BX_CPU_THIS_PTR get_TSC();
|
2020-05-21 22:58:16 +03:00
|
|
|
#if BX_SUPPORT_SVM || BX_SUPPORT_VMX
|
|
|
|
ticks = BX_CPU_THIS_PTR get_TSC_VMXAdjust(ticks);
|
|
|
|
#endif
|
2009-01-31 13:43:24 +03:00
|
|
|
|
2011-12-25 23:35:29 +04:00
|
|
|
RAX = GET32L(ticks);
|
|
|
|
RDX = GET32H(ticks);
|
2011-09-06 19:35:39 +04:00
|
|
|
|
2011-12-25 23:35:29 +04:00
|
|
|
BX_DEBUG(("RDTSC: ticks 0x%08x:%08x", EDX, EAX));
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RDTSCP(bxInstruction_c *i)
|
2005-08-05 16:47:33 +04:00
|
|
|
{
|
2011-01-21 19:07:51 +03:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
2010-03-15 16:47:18 +03:00
|
|
|
#if BX_SUPPORT_VMX
|
2019-10-24 22:49:25 +03:00
|
|
|
// RDTSCP will always #UD in legacy VMX mode, the #UD takes priority over any other exception the instruction may incur.
|
2010-03-15 18:48:01 +03:00
|
|
|
if (BX_CPU_THIS_PTR in_vmx_guest) {
|
|
|
|
if (! SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_RDTSCP)) {
|
2013-12-03 00:06:59 +04:00
|
|
|
BX_ERROR(("%s in VMX guest: not allowed to use instruction !", i->getIaOpcodeNameShort()));
|
2010-03-15 18:48:01 +03:00
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
|
|
|
}
|
2010-03-15 16:47:18 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-12-25 23:35:29 +04:00
|
|
|
if (BX_CPU_THIS_PTR cr4.get_TSD() && CPL != 0) {
|
2013-12-03 00:06:59 +04:00
|
|
|
BX_ERROR(("%s: not allowed to use instruction !", i->getIaOpcodeNameShort()));
|
2011-12-25 23:35:29 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
|
|
|
}
|
2011-07-10 02:28:08 +04:00
|
|
|
|
|
|
|
#if BX_SUPPORT_VMX
|
2012-01-18 01:50:15 +04:00
|
|
|
if (BX_CPU_THIS_PTR in_vmx_guest) {
|
|
|
|
if (VMEXIT(VMX_VM_EXEC_CTRL2_RDTSC_VMEXIT)) {
|
2012-07-26 20:03:26 +04:00
|
|
|
VMexit(VMX_VMEXIT_RDTSCP, 0);
|
2012-01-18 01:50:15 +04:00
|
|
|
}
|
|
|
|
}
|
2011-07-10 02:28:08 +04:00
|
|
|
#endif
|
|
|
|
|
2011-12-25 23:35:29 +04:00
|
|
|
#if BX_SUPPORT_SVM
|
|
|
|
if (BX_CPU_THIS_PTR in_svm_guest)
|
2011-12-27 23:42:11 +04:00
|
|
|
if (SVM_INTERCEPT(SVM_INTERCEPT1_RDTSCP)) Svm_Vmexit(SVM_VMEXIT_RDTSCP);
|
2011-12-25 23:35:29 +04:00
|
|
|
#endif
|
2011-07-10 02:28:08 +04:00
|
|
|
|
2011-12-25 23:35:29 +04:00
|
|
|
// return ticks
|
|
|
|
Bit64u ticks = BX_CPU_THIS_PTR get_TSC();
|
2020-05-21 22:58:16 +03:00
|
|
|
#if BX_SUPPORT_SVM || BX_SUPPORT_VMX
|
|
|
|
ticks = BX_CPU_THIS_PTR get_TSC_VMXAdjust(ticks);
|
|
|
|
#endif
|
2011-12-25 23:35:29 +04:00
|
|
|
|
|
|
|
RAX = GET32L(ticks);
|
|
|
|
RDX = GET32H(ticks);
|
2015-02-19 23:23:08 +03:00
|
|
|
RCX = BX_CPU_THIS_PTR msr.tsc_aux;
|
2011-07-10 02:28:08 +04:00
|
|
|
|
2005-08-05 16:47:33 +04:00
|
|
|
#endif
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2011-01-21 19:07:51 +03:00
|
|
|
}
|
2005-08-05 16:47:33 +04:00
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RDPID_Ed(bxInstruction_c *i)
|
2016-04-15 14:35:32 +03:00
|
|
|
{
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
|
|
|
|
#if BX_SUPPORT_VMX
|
|
|
|
// RDTSCP will always #UD in legacy VMX mode
|
|
|
|
if (BX_CPU_THIS_PTR in_vmx_guest) {
|
|
|
|
if (! SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_RDTSCP)) {
|
|
|
|
BX_ERROR(("%s in VMX guest: not allowed to use instruction !", i->getIaOpcodeNameShort()));
|
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
BX_WRITE_32BIT_REGZ(i->dst(), BX_CPU_THIS_PTR msr.tsc_aux);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
|
|
|
}
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SYSENTER(bxInstruction_c *i)
|
2003-01-20 23:10:31 +03:00
|
|
|
{
|
2010-02-26 14:44:50 +03:00
|
|
|
#if BX_CPU_LEVEL >= 6
|
2008-04-21 01:44:13 +04:00
|
|
|
if (real_mode()) {
|
2013-12-03 00:06:59 +04:00
|
|
|
BX_ERROR(("%s: not recognized in real mode !", i->getIaOpcodeNameShort()));
|
2010-03-14 18:51:27 +03:00
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
2003-01-20 23:10:31 +03:00
|
|
|
}
|
2006-02-28 22:50:08 +03:00
|
|
|
if ((BX_CPU_THIS_PTR msr.sysenter_cs_msr & BX_SELECTOR_RPL_MASK) == 0) {
|
2007-10-12 01:29:01 +04:00
|
|
|
BX_ERROR(("SYSENTER with zero sysenter_cs_msr !"));
|
2010-03-14 18:51:27 +03:00
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
2003-01-20 23:10:31 +03:00
|
|
|
}
|
|
|
|
|
2003-05-11 02:25:55 +04:00
|
|
|
invalidate_prefetch_q();
|
2003-01-20 23:10:31 +03:00
|
|
|
|
2015-01-11 23:45:39 +03:00
|
|
|
BX_INSTR_FAR_BRANCH_ORIGIN();
|
|
|
|
|
2005-09-29 21:32:32 +04:00
|
|
|
BX_CPU_THIS_PTR clear_VM(); // do this just like the book says to do
|
|
|
|
BX_CPU_THIS_PTR clear_IF();
|
|
|
|
BX_CPU_THIS_PTR clear_RF();
|
2003-01-20 23:10:31 +03:00
|
|
|
|
2008-04-15 18:41:50 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
if (long_mode()) {
|
|
|
|
if (!IsCanonical(BX_CPU_THIS_PTR msr.sysenter_eip_msr)) {
|
|
|
|
BX_ERROR(("SYSENTER with non-canonical SYSENTER_EIP_MSR !"));
|
2010-03-14 18:51:27 +03:00
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
2008-04-15 18:41:50 +04:00
|
|
|
}
|
|
|
|
if (!IsCanonical(BX_CPU_THIS_PTR msr.sysenter_esp_msr)) {
|
|
|
|
BX_ERROR(("SYSENTER with non-canonical SYSENTER_ESP_MSR !"));
|
2010-03-14 18:51:27 +03:00
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
2008-04-15 18:41:50 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-12-20 10:42:07 +03:00
|
|
|
#if BX_SUPPORT_CET
|
|
|
|
if (ShadowStackEnabled(CPL))
|
|
|
|
BX_CPU_THIS_PTR msr.ia32_pl_ssp[3] = SSP;
|
|
|
|
if (ShadowStackEnabled(0)) SSP = 0;
|
|
|
|
track_indirect(0);
|
|
|
|
#endif
|
|
|
|
|
2006-06-12 01:37:22 +04:00
|
|
|
parse_selector(BX_CPU_THIS_PTR msr.sysenter_cs_msr & BX_SELECTOR_RPL_MASK,
|
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector);
|
|
|
|
|
2015-01-25 23:55:10 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK | SegAccessROK4G | SegAccessWOK4G;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = 1; /* data/code segment */
|
2009-10-07 19:45:15 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.type = BX_CODE_EXEC_READ_ACCESSED;
|
2003-01-20 23:10:31 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = 0; // base address
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xFFFFFFFF; // scaled segment limit
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; // 4k granularity
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0; // available for use by system
|
2008-04-15 18:41:50 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b = !long_mode();
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.l = long_mode();
|
|
|
|
#endif
|
2003-01-20 23:10:31 +03:00
|
|
|
|
2008-04-20 22:17:14 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
handleCpuModeChange(); // mode change could happen only when in long_mode()
|
2009-03-11 01:28:08 +03:00
|
|
|
#else
|
2010-04-22 21:51:37 +04:00
|
|
|
updateFetchModeMask(/* CS reloaded */);
|
2008-04-20 22:17:14 +04:00
|
|
|
#endif
|
|
|
|
|
2010-09-07 23:54:50 +04:00
|
|
|
#if BX_SUPPORT_ALIGNMENT_CHECK
|
2008-09-08 19:45:57 +04:00
|
|
|
BX_CPU_THIS_PTR alignment_check_mask = 0; // CPL=0
|
2007-11-21 00:22:03 +03:00
|
|
|
#endif
|
|
|
|
|
2006-06-12 01:37:22 +04:00
|
|
|
parse_selector((BX_CPU_THIS_PTR msr.sysenter_cs_msr + 8) & BX_SELECTOR_RPL_MASK,
|
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector);
|
|
|
|
|
2015-01-25 23:55:10 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK | SegAccessROK4G | SegAccessWOK4G;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.dpl = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.segment = 1; /* data/code segment */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
2003-01-20 23:10:31 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.base = 0; // base address
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit_scaled = 0xFFFFFFFF; // scaled segment limit
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.g = 1; // 4k granularity
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b = 1; // 32-bit mode
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.avl = 0; // available for use by system
|
2008-04-15 18:41:50 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.l = 0;
|
|
|
|
#endif
|
2003-01-20 23:10:31 +03:00
|
|
|
|
2008-04-15 18:41:50 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
if (long_mode()) {
|
|
|
|
RSP = BX_CPU_THIS_PTR msr.sysenter_esp_msr;
|
|
|
|
RIP = BX_CPU_THIS_PTR msr.sysenter_eip_msr;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
ESP = (Bit32u) BX_CPU_THIS_PTR msr.sysenter_esp_msr;
|
|
|
|
EIP = (Bit32u) BX_CPU_THIS_PTR msr.sysenter_eip_msr;
|
|
|
|
}
|
2008-01-18 11:57:35 +03:00
|
|
|
|
|
|
|
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_SYSENTER,
|
2015-01-11 23:45:39 +03:00
|
|
|
FAR_BRANCH_PREV_CS, FAR_BRANCH_PREV_RIP,
|
2008-04-15 18:41:50 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, RIP);
|
2003-01-20 23:10:31 +03:00
|
|
|
#endif
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_TRACE(i);
|
2003-01-20 23:10:31 +03:00
|
|
|
}
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SYSEXIT(bxInstruction_c *i)
|
2003-01-20 23:10:31 +03:00
|
|
|
{
|
2010-02-26 14:44:50 +03:00
|
|
|
#if BX_CPU_LEVEL >= 6
|
2008-04-21 01:44:13 +04:00
|
|
|
if (real_mode() || CPL != 0) {
|
|
|
|
BX_ERROR(("SYSEXIT from real mode or with CPL<>0 !"));
|
2010-03-14 18:51:27 +03:00
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
2003-01-20 23:10:31 +03:00
|
|
|
}
|
2006-02-28 22:50:08 +03:00
|
|
|
if ((BX_CPU_THIS_PTR msr.sysenter_cs_msr & BX_SELECTOR_RPL_MASK) == 0) {
|
2007-10-12 01:29:01 +04:00
|
|
|
BX_ERROR(("SYSEXIT with zero sysenter_cs_msr !"));
|
2010-03-14 18:51:27 +03:00
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
2003-01-20 23:10:31 +03:00
|
|
|
}
|
2008-04-15 18:41:50 +04:00
|
|
|
|
2010-04-03 01:22:17 +04:00
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
2015-01-11 23:45:39 +03:00
|
|
|
BX_INSTR_FAR_BRANCH_ORIGIN();
|
|
|
|
|
2008-04-15 18:41:50 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
if (i->os64L()) {
|
|
|
|
if (!IsCanonical(RDX)) {
|
2010-04-03 01:22:17 +04:00
|
|
|
BX_ERROR(("SYSEXIT with non-canonical RDX (RIP) pointer !"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
2008-04-15 18:41:50 +04:00
|
|
|
}
|
|
|
|
if (!IsCanonical(RCX)) {
|
2010-04-03 01:22:17 +04:00
|
|
|
BX_ERROR(("SYSEXIT with non-canonical RCX (RSP) pointer !"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
2008-04-15 18:41:50 +04:00
|
|
|
}
|
2003-01-20 23:10:31 +03:00
|
|
|
|
2008-04-15 18:41:50 +04:00
|
|
|
parse_selector(((BX_CPU_THIS_PTR msr.sysenter_cs_msr + 32) & BX_SELECTOR_RPL_MASK) | 3,
|
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector);
|
2006-06-12 01:37:22 +04:00
|
|
|
|
2015-01-25 23:55:10 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK | SegAccessROK4G | SegAccessWOK4G;
|
2008-04-15 18:41:50 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl = 3;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = 1; /* data/code segment */
|
2009-10-07 19:45:15 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.type = BX_CODE_EXEC_READ_ACCESSED;
|
2008-04-15 18:41:50 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = 0; // base address
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xFFFFFFFF; // scaled segment limit
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; // 4k granularity
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0; // available for use by system
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.l = 1;
|
|
|
|
|
|
|
|
RSP = RCX;
|
|
|
|
RIP = RDX;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
parse_selector(((BX_CPU_THIS_PTR msr.sysenter_cs_msr + 16) & BX_SELECTOR_RPL_MASK) | 3,
|
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector);
|
|
|
|
|
2015-01-25 23:55:10 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK | SegAccessROK4G | SegAccessWOK4G;
|
2008-04-15 18:41:50 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl = 3;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = 1; /* data/code segment */
|
2009-10-07 19:45:15 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.type = BX_CODE_EXEC_READ_ACCESSED;
|
2008-04-15 18:41:50 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = 0; // base address
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xFFFFFFFF; // scaled segment limit
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; // 4k granularity
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0; // available for use by system
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b = 1;
|
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.l = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
ESP = ECX;
|
|
|
|
EIP = EDX;
|
|
|
|
}
|
2003-01-20 23:10:31 +03:00
|
|
|
|
2008-04-20 22:17:14 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
handleCpuModeChange(); // mode change could happen only when in long_mode()
|
2009-03-11 01:28:08 +03:00
|
|
|
#else
|
2010-04-22 21:51:37 +04:00
|
|
|
updateFetchModeMask(/* CS reloaded */);
|
2008-04-20 22:17:14 +04:00
|
|
|
#endif
|
|
|
|
|
2010-04-22 21:51:37 +04:00
|
|
|
handleAlignmentCheck(/* CPL change */);
|
2007-11-21 00:22:03 +03:00
|
|
|
|
2008-04-15 18:41:50 +04:00
|
|
|
parse_selector(((BX_CPU_THIS_PTR msr.sysenter_cs_msr + (i->os64L() ? 40:24)) & BX_SELECTOR_RPL_MASK) | 3,
|
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector);
|
2006-06-12 01:37:22 +04:00
|
|
|
|
2015-01-25 23:55:10 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK | SegAccessROK4G | SegAccessWOK4G;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.dpl = 3;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.segment = 1; /* data/code segment */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
2003-01-20 23:10:31 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.base = 0; // base address
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit_scaled = 0xFFFFFFFF; // scaled segment limit
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.g = 1; // 4k granularity
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b = 1; // 32-bit mode
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.avl = 0; // available for use by system
|
2008-04-15 18:41:50 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.l = 0;
|
|
|
|
#endif
|
2008-01-18 11:57:35 +03:00
|
|
|
|
2019-12-20 10:42:07 +03:00
|
|
|
#if BX_SUPPORT_CET
|
|
|
|
if (ShadowStackEnabled(CPL))
|
|
|
|
SSP = BX_CPU_THIS_PTR msr.ia32_pl_ssp[3];
|
|
|
|
#endif
|
|
|
|
|
2008-01-18 11:57:35 +03:00
|
|
|
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_SYSEXIT,
|
2015-01-11 23:45:39 +03:00
|
|
|
FAR_BRANCH_PREV_CS, FAR_BRANCH_PREV_RIP,
|
2008-04-15 18:41:50 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, RIP);
|
2003-01-20 23:10:31 +03:00
|
|
|
#endif
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_TRACE(i);
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SYSCALL(bxInstruction_c *i)
|
2005-03-03 23:24:52 +03:00
|
|
|
{
|
2011-08-31 01:32:40 +04:00
|
|
|
#if BX_CPU_LEVEL >= 5
|
2005-03-03 23:24:52 +03:00
|
|
|
bx_address temp_RIP;
|
|
|
|
|
2006-06-10 02:29:07 +04:00
|
|
|
BX_DEBUG(("Execute SYSCALL instruction"));
|
|
|
|
|
2008-04-01 00:56:27 +04:00
|
|
|
if (!BX_CPU_THIS_PTR efer.get_SCE()) {
|
2010-03-14 18:51:27 +03:00
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
2005-03-03 23:24:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
invalidate_prefetch_q();
|
|
|
|
|
2015-01-11 23:45:39 +03:00
|
|
|
BX_INSTR_FAR_BRANCH_ORIGIN();
|
|
|
|
|
2019-12-20 10:42:07 +03:00
|
|
|
#if BX_SUPPORT_CET
|
|
|
|
unsigned old_CPL = CPL;
|
|
|
|
#endif
|
|
|
|
|
2011-08-31 01:32:40 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
2008-04-15 18:41:50 +04:00
|
|
|
if (long_mode())
|
2005-03-03 23:24:52 +03:00
|
|
|
{
|
|
|
|
RCX = RIP;
|
2005-10-17 17:06:09 +04:00
|
|
|
R11 = read_eflags() & ~(EFlagsRFMask);
|
2005-03-03 23:24:52 +03:00
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
|
2015-02-19 23:23:08 +03:00
|
|
|
temp_RIP = BX_CPU_THIS_PTR msr.lstar;
|
2005-03-03 23:24:52 +03:00
|
|
|
}
|
|
|
|
else {
|
2015-02-19 23:23:08 +03:00
|
|
|
temp_RIP = BX_CPU_THIS_PTR msr.cstar;
|
2005-03-03 23:24:52 +03:00
|
|
|
}
|
|
|
|
|
2006-06-12 01:37:22 +04:00
|
|
|
// set up CS segment, flat, 64-bit DPL=0
|
2015-07-13 23:24:14 +03:00
|
|
|
parse_selector((BX_CPU_THIS_PTR msr.star >> 32) & BX_SELECTOR_RPL_MASK,
|
2006-06-12 01:37:22 +04:00
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector);
|
|
|
|
|
2015-01-25 23:55:10 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK | SegAccessROK4G | SegAccessWOK4G;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = 1; /* data/code segment */
|
2009-10-07 19:45:15 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.type = BX_CODE_EXEC_READ_ACCESSED;
|
2006-06-12 01:37:22 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = 0; /* base address */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xFFFFFFFF; /* scaled segment limit */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; /* 4k granularity */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.l = 1; /* 64-bit code */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0; /* available for use by system */
|
2005-03-03 23:24:52 +03:00
|
|
|
|
2008-04-20 22:17:14 +04:00
|
|
|
handleCpuModeChange(); // mode change could only happen when in long_mode()
|
|
|
|
|
2010-07-23 00:12:25 +04:00
|
|
|
#if BX_SUPPORT_ALIGNMENT_CHECK
|
2008-09-08 19:45:57 +04:00
|
|
|
BX_CPU_THIS_PTR alignment_check_mask = 0; // CPL=0
|
2007-11-21 00:22:03 +03:00
|
|
|
#endif
|
|
|
|
|
2006-06-12 01:37:22 +04:00
|
|
|
// set up SS segment, flat, 64-bit DPL=0
|
2015-07-13 23:24:14 +03:00
|
|
|
parse_selector(((BX_CPU_THIS_PTR msr.star >> 32) + 8) & BX_SELECTOR_RPL_MASK,
|
2006-06-12 01:37:22 +04:00
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector);
|
|
|
|
|
2015-01-25 23:55:10 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK | SegAccessROK4G | SegAccessWOK4G;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.dpl = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.segment = 1; /* data/code segment */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
2006-06-12 01:37:22 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.base = 0; /* base address */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit_scaled = 0xFFFFFFFF; /* scaled segment limit */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.g = 1; /* 4k granularity */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b = 1; /* 32 bit stack */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.l = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.avl = 0; /* available for use by system */
|
2005-03-03 23:24:52 +03:00
|
|
|
|
2015-02-19 23:23:08 +03:00
|
|
|
writeEFlags(read_eflags() & ~(BX_CPU_THIS_PTR msr.fmask) & ~(EFlagsRFMask), EFlagsValidMask);
|
2005-03-03 23:24:52 +03:00
|
|
|
RIP = temp_RIP;
|
|
|
|
}
|
2011-08-31 01:32:40 +04:00
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
2005-03-03 23:24:52 +03:00
|
|
|
// legacy mode
|
|
|
|
|
|
|
|
ECX = EIP;
|
2015-07-13 23:24:14 +03:00
|
|
|
temp_RIP = (Bit32u)(BX_CPU_THIS_PTR msr.star);
|
2005-03-03 23:24:52 +03:00
|
|
|
|
2006-06-12 01:37:22 +04:00
|
|
|
// set up CS segment, flat, 32-bit DPL=0
|
2015-07-13 23:24:14 +03:00
|
|
|
parse_selector((BX_CPU_THIS_PTR msr.star >> 32) & BX_SELECTOR_RPL_MASK,
|
2006-06-12 01:37:22 +04:00
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector);
|
|
|
|
|
2015-01-25 23:55:10 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK | SegAccessROK4G | SegAccessWOK4G;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = 1; /* data/code segment */
|
2009-10-07 19:45:15 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.type = BX_CODE_EXEC_READ_ACCESSED;
|
2006-06-12 01:37:22 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = 0; /* base address */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xFFFFFFFF; /* scaled segment limit */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; /* 4k granularity */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b = 1;
|
2011-08-31 02:00:27 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
2006-06-12 01:37:22 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.l = 0; /* 32-bit code */
|
2011-08-31 02:00:27 +04:00
|
|
|
#endif
|
2006-06-12 01:37:22 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0; /* available for use by system */
|
2005-03-03 23:24:52 +03:00
|
|
|
|
2010-04-22 21:51:37 +04:00
|
|
|
updateFetchModeMask(/* CS reloaded */);
|
2005-03-03 23:24:52 +03:00
|
|
|
|
2010-07-23 00:12:25 +04:00
|
|
|
#if BX_SUPPORT_ALIGNMENT_CHECK
|
2008-09-08 19:45:57 +04:00
|
|
|
BX_CPU_THIS_PTR alignment_check_mask = 0; // CPL=0
|
2007-11-21 00:22:03 +03:00
|
|
|
#endif
|
|
|
|
|
2006-06-12 01:37:22 +04:00
|
|
|
// set up SS segment, flat, 32-bit DPL=0
|
2015-07-13 23:24:14 +03:00
|
|
|
parse_selector(((BX_CPU_THIS_PTR msr.star >> 32) + 8) & BX_SELECTOR_RPL_MASK,
|
2006-06-12 01:37:22 +04:00
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector);
|
|
|
|
|
2015-01-25 23:55:10 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK | SegAccessROK4G | SegAccessWOK4G;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.dpl = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.segment = 1; /* data/code segment */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
2006-06-12 01:37:22 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.base = 0; /* base address */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit_scaled = 0xFFFFFFFF; /* scaled segment limit */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.g = 1; /* 4k granularity */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b = 1; /* 32 bit stack */
|
2011-08-31 02:00:27 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
2006-06-12 01:37:22 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.l = 0;
|
2011-08-31 02:00:27 +04:00
|
|
|
#endif
|
2006-06-12 01:37:22 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.avl = 0; /* available for use by system */
|
|
|
|
|
|
|
|
BX_CPU_THIS_PTR clear_VM();
|
|
|
|
BX_CPU_THIS_PTR clear_IF();
|
|
|
|
BX_CPU_THIS_PTR clear_RF();
|
2005-03-03 23:24:52 +03:00
|
|
|
RIP = temp_RIP;
|
|
|
|
}
|
2008-01-18 11:57:35 +03:00
|
|
|
|
2019-12-20 10:42:07 +03:00
|
|
|
#if BX_SUPPORT_CET
|
|
|
|
if (ShadowStackEnabled(old_CPL))
|
|
|
|
BX_CPU_THIS_PTR msr.ia32_pl_ssp[3] = SSP;
|
|
|
|
if (ShadowStackEnabled(0)) SSP = 0;
|
|
|
|
track_indirect(0);
|
|
|
|
#endif
|
|
|
|
|
2008-01-18 11:57:35 +03:00
|
|
|
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_SYSCALL,
|
2015-01-11 23:45:39 +03:00
|
|
|
FAR_BRANCH_PREV_CS, FAR_BRANCH_PREV_RIP,
|
2008-01-18 11:57:35 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, RIP);
|
2011-08-31 01:32:40 +04:00
|
|
|
#endif
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_TRACE(i);
|
2005-03-03 23:24:52 +03:00
|
|
|
}
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SYSRET(bxInstruction_c *i)
|
2005-03-03 23:24:52 +03:00
|
|
|
{
|
2011-08-31 01:32:40 +04:00
|
|
|
#if BX_CPU_LEVEL >= 5
|
2005-03-03 23:24:52 +03:00
|
|
|
bx_address temp_RIP;
|
|
|
|
|
2006-06-10 02:29:07 +04:00
|
|
|
BX_DEBUG(("Execute SYSRET instruction"));
|
|
|
|
|
2008-04-01 00:56:27 +04:00
|
|
|
if (!BX_CPU_THIS_PTR efer.get_SCE()) {
|
2010-03-14 18:51:27 +03:00
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
2005-03-03 23:24:52 +03:00
|
|
|
}
|
|
|
|
|
2008-04-15 18:41:50 +04:00
|
|
|
if(!protected_mode() || CPL != 0) {
|
2013-12-03 00:06:59 +04:00
|
|
|
BX_ERROR(("%s: priveledge check failed, generate #GP(0)", i->getIaOpcodeNameShort()));
|
2010-03-14 18:51:27 +03:00
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
2005-03-03 23:24:52 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
invalidate_prefetch_q();
|
2008-02-03 00:46:54 +03:00
|
|
|
|
2015-01-11 23:45:39 +03:00
|
|
|
BX_INSTR_FAR_BRANCH_ORIGIN();
|
|
|
|
|
2011-08-31 01:32:40 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
2005-03-03 23:24:52 +03:00
|
|
|
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64)
|
|
|
|
{
|
2006-06-12 01:37:22 +04:00
|
|
|
if (i->os64L()) {
|
2010-04-03 01:22:17 +04:00
|
|
|
if (!IsCanonical(RCX)) {
|
|
|
|
BX_ERROR(("SYSRET: canonical failure for RCX (RIP)"));
|
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
|
|
|
}
|
|
|
|
|
2006-06-12 01:37:22 +04:00
|
|
|
// Return to 64-bit mode, set up CS segment, flat, 64-bit DPL=3
|
2015-07-13 23:24:14 +03:00
|
|
|
parse_selector((((BX_CPU_THIS_PTR msr.star >> 48) + 16) & BX_SELECTOR_RPL_MASK) | 3,
|
2006-06-12 01:37:22 +04:00
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector);
|
|
|
|
|
2015-01-25 23:55:10 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK | SegAccessROK4G | SegAccessWOK4G;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl = 3;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = 1; /* data/code segment */
|
2009-10-07 19:45:15 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.type = BX_CODE_EXEC_READ_ACCESSED;
|
2006-06-12 01:37:22 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = 0; /* base address */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xFFFFFFFF; /* scaled segment limit */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; /* 4k granularity */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b = 0;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.l = 1; /* 64-bit code */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0; /* available for use by system */
|
2005-03-03 23:24:52 +03:00
|
|
|
|
|
|
|
temp_RIP = RCX;
|
|
|
|
}
|
2006-06-12 01:37:22 +04:00
|
|
|
else {
|
|
|
|
// Return to 32-bit compatibility mode, set up CS segment, flat, 32-bit DPL=3
|
2015-07-13 23:24:14 +03:00
|
|
|
parse_selector((BX_CPU_THIS_PTR msr.star >> 48) | 3,
|
2006-06-12 01:37:22 +04:00
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector);
|
|
|
|
|
2015-01-25 23:55:10 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK | SegAccessROK4G | SegAccessWOK4G;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl = 3;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = 1; /* data/code segment */
|
2009-10-07 19:45:15 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.type = BX_CODE_EXEC_READ_ACCESSED;
|
2006-06-12 01:37:22 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = 0; /* base address */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xFFFFFFFF; /* scaled segment limit */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; /* 4k granularity */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.l = 0; /* 32-bit code */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0; /* available for use by system */
|
2005-03-03 23:24:52 +03:00
|
|
|
|
|
|
|
temp_RIP = ECX;
|
|
|
|
}
|
|
|
|
|
2008-04-20 22:17:14 +04:00
|
|
|
handleCpuModeChange(); // mode change could only happen when in long64 mode
|
|
|
|
|
2010-04-22 21:51:37 +04:00
|
|
|
handleAlignmentCheck(/* CPL change */);
|
2007-11-21 00:22:03 +03:00
|
|
|
|
2006-06-12 01:37:22 +04:00
|
|
|
// SS base, limit, attributes unchanged
|
2015-07-13 23:24:14 +03:00
|
|
|
parse_selector((Bit16u)(((BX_CPU_THIS_PTR msr.star >> 48) + 8) | 3),
|
2006-06-12 01:37:22 +04:00
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector);
|
|
|
|
|
2015-01-25 23:55:10 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK | SegAccessROK4G | SegAccessWOK4G;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.dpl = 3;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.segment = 1; /* data/code segment */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
2005-03-03 23:24:52 +03:00
|
|
|
|
2007-12-23 20:21:28 +03:00
|
|
|
writeEFlags((Bit32u) R11, EFlagsValidMask);
|
2005-03-03 23:24:52 +03:00
|
|
|
}
|
2011-08-31 01:32:40 +04:00
|
|
|
else // (!64BIT_MODE)
|
|
|
|
#endif
|
|
|
|
{
|
2006-06-12 01:37:22 +04:00
|
|
|
// Return to 32-bit legacy mode, set up CS segment, flat, 32-bit DPL=3
|
2015-07-13 23:24:14 +03:00
|
|
|
parse_selector((BX_CPU_THIS_PTR msr.star >> 48) | 3,
|
2006-06-12 01:37:22 +04:00
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector);
|
|
|
|
|
2015-01-25 23:55:10 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK | SegAccessROK4G | SegAccessWOK4G;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl = 3;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = 1; /* data/code segment */
|
2009-10-07 19:45:15 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.type = BX_CODE_EXEC_READ_ACCESSED;
|
2006-06-12 01:37:22 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = 0; /* base address */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xFFFFFFFF; /* scaled segment limit */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; /* 4k granularity */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b = 1;
|
2011-08-31 02:00:27 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
2006-06-12 01:37:22 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.l = 0; /* 32-bit code */
|
2011-08-31 02:00:27 +04:00
|
|
|
#endif
|
2006-06-12 01:37:22 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0; /* available for use by system */
|
2005-03-03 23:24:52 +03:00
|
|
|
|
2010-04-22 21:51:37 +04:00
|
|
|
updateFetchModeMask(/* CS reloaded */);
|
2005-03-03 23:24:52 +03:00
|
|
|
|
2010-04-22 21:51:37 +04:00
|
|
|
handleAlignmentCheck(/* CPL change */);
|
2007-11-21 00:22:03 +03:00
|
|
|
|
2006-06-12 01:37:22 +04:00
|
|
|
// SS base, limit, attributes unchanged
|
2015-07-13 23:24:14 +03:00
|
|
|
parse_selector((Bit16u)(((BX_CPU_THIS_PTR msr.star >> 48) + 8) | 3),
|
2006-06-12 01:37:22 +04:00
|
|
|
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector);
|
2005-03-03 23:24:52 +03:00
|
|
|
|
2015-01-25 23:55:10 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK | SegAccessROK4G | SegAccessWOK4G;
|
2006-06-12 20:58:27 +04:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.p = 1;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.dpl = 3;
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.segment = 1; /* data/code segment */
|
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
2005-03-03 23:24:52 +03:00
|
|
|
|
2006-06-12 01:37:22 +04:00
|
|
|
BX_CPU_THIS_PTR assert_IF();
|
|
|
|
temp_RIP = ECX;
|
2005-03-03 23:24:52 +03:00
|
|
|
}
|
2006-06-12 01:37:22 +04:00
|
|
|
|
2008-04-20 22:10:32 +04:00
|
|
|
handleCpuModeChange();
|
|
|
|
|
2006-06-12 01:37:22 +04:00
|
|
|
RIP = temp_RIP;
|
2008-01-18 11:57:35 +03:00
|
|
|
|
2019-12-20 10:42:07 +03:00
|
|
|
#if BX_SUPPORT_CET
|
|
|
|
if (ShadowStackEnabled(CPL))
|
|
|
|
SSP = BX_CPU_THIS_PTR msr.ia32_pl_ssp[3];
|
|
|
|
#endif
|
|
|
|
|
2008-01-18 11:57:35 +03:00
|
|
|
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_SYSRET,
|
2015-01-11 23:45:39 +03:00
|
|
|
FAR_BRANCH_PREV_CS, FAR_BRANCH_PREV_RIP,
|
2008-01-18 11:57:35 +03:00
|
|
|
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, RIP);
|
2011-08-31 01:32:40 +04:00
|
|
|
#endif
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_TRACE(i);
|
2005-03-03 23:24:52 +03:00
|
|
|
}
|
|
|
|
|
2011-08-31 01:32:40 +04:00
|
|
|
#if BX_SUPPORT_X86_64
|
2012-10-07 13:16:13 +04:00
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SWAPGS(bxInstruction_c *i)
|
2002-09-25 18:09:08 +04:00
|
|
|
{
|
2003-08-30 01:20:52 +04:00
|
|
|
if(CPL != 0)
|
2010-03-14 18:51:27 +03:00
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
2003-08-30 01:20:52 +04:00
|
|
|
|
2010-03-27 19:30:01 +03:00
|
|
|
Bit64u temp_GS_base = MSR_GSBASE;
|
2015-07-13 23:24:14 +03:00
|
|
|
MSR_GSBASE = BX_CPU_THIS_PTR msr.kernelgsbase;
|
|
|
|
BX_CPU_THIS_PTR msr.kernelgsbase = temp_GS_base;
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2002-09-25 18:09:08 +04:00
|
|
|
}
|
2010-07-22 20:41:59 +04:00
|
|
|
|
|
|
|
/* F3 0F AE /0 */
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RDFSBASE_Ed(bxInstruction_c *i)
|
2010-07-22 20:41:59 +04:00
|
|
|
{
|
|
|
|
if (! BX_CPU_THIS_PTR cr4.get_FSGSBASE())
|
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
|
|
|
|
2013-09-30 23:01:42 +04:00
|
|
|
BX_WRITE_32BIT_REGZ(i->dst(), (Bit32u) MSR_FSBASE);
|
|
|
|
BX_NEXT_INSTR(i);
|
|
|
|
}
|
2011-07-07 00:01:18 +04:00
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RDFSBASE_Eq(bxInstruction_c *i)
|
2013-09-30 23:01:42 +04:00
|
|
|
{
|
|
|
|
if (! BX_CPU_THIS_PTR cr4.get_FSGSBASE())
|
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
|
|
|
|
|
|
|
BX_WRITE_64BIT_REG(i->dst(), MSR_FSBASE);
|
2011-07-07 00:01:18 +04:00
|
|
|
BX_NEXT_INSTR(i);
|
2010-07-22 20:41:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* F3 0F AE /1 */
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RDGSBASE_Ed(bxInstruction_c *i)
|
2010-07-22 20:41:59 +04:00
|
|
|
{
|
|
|
|
if (! BX_CPU_THIS_PTR cr4.get_FSGSBASE())
|
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
|
|
|
|
2013-09-30 23:01:42 +04:00
|
|
|
BX_WRITE_32BIT_REGZ(i->dst(), (Bit32u) MSR_GSBASE);
|
|
|
|
BX_NEXT_INSTR(i);
|
|
|
|
}
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RDGSBASE_Eq(bxInstruction_c *i)
|
2013-09-30 23:01:42 +04:00
|
|
|
{
|
|
|
|
if (! BX_CPU_THIS_PTR cr4.get_FSGSBASE())
|
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
2011-07-07 00:01:18 +04:00
|
|
|
|
2013-09-30 23:01:42 +04:00
|
|
|
BX_WRITE_64BIT_REG(i->dst(), MSR_GSBASE);
|
2011-07-07 00:01:18 +04:00
|
|
|
BX_NEXT_INSTR(i);
|
2010-07-22 20:41:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* F3 0F AE /2 */
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::WRFSBASE_Ed(bxInstruction_c *i)
|
2010-07-22 20:41:59 +04:00
|
|
|
{
|
|
|
|
if (! BX_CPU_THIS_PTR cr4.get_FSGSBASE())
|
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
|
|
|
|
2013-09-30 23:01:42 +04:00
|
|
|
// 32-bit value is always canonical
|
|
|
|
MSR_FSBASE = BX_READ_32BIT_REG(i->src());
|
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
|
|
|
}
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::WRFSBASE_Eq(bxInstruction_c *i)
|
2013-09-30 23:01:42 +04:00
|
|
|
{
|
|
|
|
if (! BX_CPU_THIS_PTR cr4.get_FSGSBASE())
|
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
|
|
|
|
|
|
|
Bit64u fsbase = BX_READ_64BIT_REG(i->src());
|
|
|
|
if (!IsCanonical(fsbase)) {
|
2013-12-03 00:06:59 +04:00
|
|
|
BX_ERROR(("%s: canonical failure !", i->getIaOpcodeNameShort()));
|
2013-09-30 23:01:42 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
2010-07-22 20:41:59 +04:00
|
|
|
}
|
2013-09-30 23:01:42 +04:00
|
|
|
MSR_FSBASE = fsbase;
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2010-07-22 20:41:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* F3 0F AE /3 */
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::WRGSBASE_Ed(bxInstruction_c *i)
|
2010-07-22 20:41:59 +04:00
|
|
|
{
|
|
|
|
if (! BX_CPU_THIS_PTR cr4.get_FSGSBASE())
|
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
|
|
|
|
2013-09-30 23:01:42 +04:00
|
|
|
// 32-bit value is always canonical
|
|
|
|
MSR_GSBASE = BX_READ_32BIT_REG(i->src());
|
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
|
|
|
}
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::WRGSBASE_Eq(bxInstruction_c *i)
|
2013-09-30 23:01:42 +04:00
|
|
|
{
|
|
|
|
if (! BX_CPU_THIS_PTR cr4.get_FSGSBASE())
|
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
|
|
|
|
|
|
|
Bit64u gsbase = BX_READ_64BIT_REG(i->src());
|
|
|
|
if (!IsCanonical(gsbase)) {
|
2013-12-03 00:06:59 +04:00
|
|
|
BX_ERROR(("%s: canonical failure !", i->getIaOpcodeNameShort()));
|
2013-09-30 23:01:42 +04:00
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
2010-07-22 20:41:59 +04:00
|
|
|
}
|
2013-09-30 23:01:42 +04:00
|
|
|
MSR_GSBASE = gsbase;
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2010-07-22 20:41:59 +04:00
|
|
|
}
|
2012-09-10 19:22:26 +04:00
|
|
|
|
2016-03-02 23:44:42 +03:00
|
|
|
#endif // BX_SUPPORT_X86_64
|
|
|
|
|
|
|
|
#if BX_SUPPORT_PKEYS
|
|
|
|
|
2020-05-29 15:35:30 +03:00
|
|
|
void BX_CPU_C::set_PKeys(Bit32u pkru_val, Bit32u pkrs_val)
|
2016-03-02 23:44:42 +03:00
|
|
|
{
|
2019-12-04 21:52:00 +03:00
|
|
|
BX_CPU_THIS_PTR pkru = pkru_val;
|
2020-05-29 15:35:30 +03:00
|
|
|
BX_CPU_THIS_PTR pkrs = pkrs_val;
|
2016-03-02 23:44:42 +03:00
|
|
|
|
|
|
|
for (unsigned i=0; i<16; i++) {
|
|
|
|
BX_CPU_THIS_PTR rd_pkey[i] = BX_CPU_THIS_PTR wr_pkey[i] =
|
|
|
|
TLB_SysReadOK | TLB_UserReadOK | TLB_SysWriteOK | TLB_UserWriteOK;
|
|
|
|
|
2020-05-29 15:35:30 +03:00
|
|
|
if (long_mode()) {
|
|
|
|
if (BX_CPU_THIS_PTR cr4.get_PKE()) {
|
|
|
|
// accessDisable bit set
|
|
|
|
if (pkru_val & (1<<(i*2))) {
|
|
|
|
BX_CPU_THIS_PTR rd_pkey[i] &= ~(TLB_UserReadOK | TLB_UserWriteOK);
|
|
|
|
BX_CPU_THIS_PTR wr_pkey[i] &= ~(TLB_UserReadOK | TLB_UserWriteOK);
|
|
|
|
}
|
|
|
|
|
|
|
|
// writeDisable bit set
|
|
|
|
if (pkru_val & (1<<(i*2+1))) {
|
|
|
|
BX_CPU_THIS_PTR wr_pkey[i] &= ~(TLB_UserWriteOK);
|
|
|
|
if (BX_CPU_THIS_PTR cr0.get_WP())
|
|
|
|
BX_CPU_THIS_PTR wr_pkey[i] &= ~(TLB_SysWriteOK);
|
|
|
|
}
|
2016-03-20 00:15:56 +03:00
|
|
|
}
|
2020-05-29 15:35:30 +03:00
|
|
|
|
|
|
|
if (BX_CPU_THIS_PTR cr4.get_PKS()) {
|
|
|
|
// accessDisable bit set
|
|
|
|
if (pkrs_val & (1<<(i*2))) {
|
|
|
|
BX_CPU_THIS_PTR rd_pkey[i] &= ~(TLB_SysReadOK | TLB_SysWriteOK);
|
|
|
|
BX_CPU_THIS_PTR wr_pkey[i] &= ~(TLB_SysReadOK | TLB_SysWriteOK);
|
|
|
|
}
|
2016-03-02 23:44:42 +03:00
|
|
|
|
2020-05-29 15:35:30 +03:00
|
|
|
// writeDisable bit set
|
|
|
|
if (pkrs_val & (1<<(i*2+1))) {
|
|
|
|
if (BX_CPU_THIS_PTR cr0.get_WP())
|
|
|
|
BX_CPU_THIS_PTR wr_pkey[i] &= ~(TLB_SysWriteOK);
|
|
|
|
}
|
2016-03-20 00:15:56 +03:00
|
|
|
}
|
2016-03-02 23:44:42 +03:00
|
|
|
}
|
2019-12-20 10:42:07 +03:00
|
|
|
|
|
|
|
#if BX_SUPPORT_CET
|
|
|
|
// replicate pkey access bits for shadow stack checks
|
|
|
|
BX_CPU_THIS_PTR rd_pkey[i] |= BX_CPU_THIS_PTR rd_pkey[i]<<4;
|
|
|
|
BX_CPU_THIS_PTR wr_pkey[i] |= BX_CPU_THIS_PTR wr_pkey[i]<<4;
|
|
|
|
#endif
|
2016-03-02 23:44:42 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RDPKRU(bxInstruction_c *i)
|
2016-03-02 23:44:42 +03:00
|
|
|
{
|
|
|
|
if (! BX_CPU_THIS_PTR cr4.get_PKE())
|
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
|
|
|
|
|
|
|
if (ECX != 0)
|
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
|
|
|
|
|
|
|
RAX = BX_CPU_THIS_PTR pkru;
|
|
|
|
RDX = 0;
|
2016-04-15 14:35:32 +03:00
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2016-03-02 23:44:42 +03:00
|
|
|
}
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::WRPKRU(bxInstruction_c *i)
|
2016-03-02 23:44:42 +03:00
|
|
|
{
|
|
|
|
if (! BX_CPU_THIS_PTR cr4.get_PKE())
|
|
|
|
exception(BX_UD_EXCEPTION, 0);
|
|
|
|
|
|
|
|
if ((ECX|EDX) != 0)
|
|
|
|
exception(BX_GP_EXCEPTION, 0);
|
|
|
|
|
2020-05-29 15:35:30 +03:00
|
|
|
BX_CPU_THIS_PTR set_PKeys(EAX, BX_CPU_THIS_PTR pkrs);
|
2016-04-15 14:35:32 +03:00
|
|
|
|
|
|
|
BX_NEXT_TRACE(i);
|
2016-03-02 23:44:42 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif // BX_SUPPORT_PKEYS
|