VBoxRecompiler.c revision 949e540380e375caee37199f0a6f5ff1eb97636b
/* $Id$ */
/** @file
* VBox Recompiler - QEMU.
*/
/*
* Copyright (C) 2006-2007 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_REM
#include "vl.h"
#include "osdep.h"
#include "exec-all.h"
#include "config.h"
#include "cpu-all.h"
#include "REMInternal.h"
#include <iprt/semaphore.h>
/* Don't wanna include everything. */
extern void cpu_exec_init_all(unsigned long tb_size);
#ifdef VBOX_STRICT
#endif
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** Copy 80-bit fpu register at pSrc to pDst.
* This is probably faster than *calling* memcpy.
*/
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** @todo Move stats to REM::s some rainy day we have nothing do to. */
#ifdef VBOX_WITH_STATISTICS
static STAMPROFILEADV gStatCompilationQEmu;
static STAMPROFILEADV gStatRunCodeQEmu;
static STAMPROFILEADV gStatTotalTimeQEmu;
static STAMPROFILEADV gStatTimers;
static STAMPROFILEADV gStatTBLookup;
static STAMPROFILEADV gStatIRQ;
static STAMPROFILEADV gStatRawCheck;
static STAMPROFILEADV gStatMemRead;
static STAMPROFILEADV gStatMemWrite;
static STAMPROFILE gStatGCPhys2HCVirt;
static STAMPROFILE gStatHCVirt2GCPhys;
static STAMCOUNTER gStatCpuGetTSC;
static STAMCOUNTER gStatRefuseTFInhibit;
static STAMCOUNTER gStatRefuseVM86;
static STAMCOUNTER gStatRefusePaging;
static STAMCOUNTER gStatRefusePAE;
static STAMCOUNTER gStatRefuseIOPLNot0;
static STAMCOUNTER gStatRefuseIF0;
static STAMCOUNTER gStatRefuseCode16;
static STAMCOUNTER gStatRefuseWP0;
static STAMCOUNTER gStatRefuseRing1or2;
static STAMCOUNTER gStatRefuseCanExecute;
static STAMCOUNTER gStatREMGDTChange;
static STAMCOUNTER gStatREMIDTChange;
static STAMCOUNTER gStatREMLDTRChange;
static STAMCOUNTER gStatREMTRChange;
static STAMCOUNTER gStatFlushTBs;
#endif
/*
* Global stuff.
*/
/** MMIO read callbacks. */
{
};
/** MMIO write callbacks. */
{
};
/** Handler read callbacks. */
{
};
/** Handler write callbacks. */
{
};
/*
* Debugger commands.
*/
static DECLCALLBACK(int) remR3CmdDisasEnableStepping(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
/** '.remstep' arguments. */
static const DBGCVARDESC g_aArgRemStep[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
};
/** Command descriptors. */
{
{
.pszCmd ="remstep",
.cArgsMin = 0,
.cArgsMax = 1,
.paArgDescs = &g_aArgRemStep[0],
.pResultDesc = NULL,
.fFlags = 0,
.pszDescription = "Enable or disable the single stepping with logged disassembly. "
"If no arguments show the current state."
}
};
#endif
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
extern int testmath(void);
/* Put them here to avoid unused variable warning. */
#if !defined(IPRT_NO_CRT) && (defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_WINDOWS))
//AssertCompileMemberSize(REM, Env, REM_ENV_SIZE);
/* Why did this have to be identical?? */
#else
#endif
/**
* Initializes the REM.
*
* @returns VBox status code.
* @param pVM The VM to operate on.
*/
{
int rc;
#ifdef VBOX_ENABLE_VBOXREM64
LogRel(("Using 64-bit aware REM\n"));
#endif
/*
* Assert sanity.
*/
AssertReleaseMsg(sizeof(pVM->rem.padding) >= sizeof(pVM->rem.s), ("%#x >= %#x; sizeof(Env)=%#x\n", sizeof(pVM->rem.padding), sizeof(pVM->rem.s), sizeof(pVM->rem.s.Env)));
AssertReleaseMsg(sizeof(pVM->rem.s.Env) <= REM_ENV_SIZE, ("%#x == %#x\n", sizeof(pVM->rem.s.Env), REM_ENV_SIZE));
#endif
/*
* Init some internal data members.
*/
#ifdef CPU_RAW_MODE_INIT
#endif
/* ctx. */
AssertMsg(MMR3PhysGetRamSize(pVM) == 0, ("Init order have changed! REM depends on notification about ALL physical memory registrations\n"));
/* ignore all notifications */
/*
* Init the recompiler.
*/
{
AssertMsgFailed(("cpu_x86_init failed - impossible!\n"));
return VERR_GENERAL_FAILURE;
}
CPUMGetGuestCpuId(pVM, 1, &u32Dummy, &u32Dummy, &pVM->rem.s.Env.cpuid_ext_features, &pVM->rem.s.Env.cpuid_features);
CPUMGetGuestCpuId(pVM, 0x80000001, &u32Dummy, &u32Dummy, &pVM->rem.s.Env.cpuid_ext3_features, &pVM->rem.s.Env.cpuid_ext2_features);
/* allocate code buffer for single instruction emulation. */
AssertMsgReturn(pVM->rem.s.Env.pvCodeBuffer, ("Failed to allocate code buffer!\n"), VERR_NO_MEMORY);
/* finally, set the cpu_single_env global. */
/* Nothing is pending by default */
/*
* Register ram types.
*/
AssertReleaseMsg(pVM->rem.s.iMMIOMemType >= 0, ("pVM->rem.s.iMMIOMemType=%d\n", pVM->rem.s.iMMIOMemType));
pVM->rem.s.iHandlerMemType = cpu_register_io_memory(-1, g_apfnHandlerRead, g_apfnHandlerWrite, pVM);
AssertReleaseMsg(pVM->rem.s.iHandlerMemType >= 0, ("pVM->rem.s.iHandlerMemType=%d\n", pVM->rem.s.iHandlerMemType));
Log2(("REM: iMMIOMemType=%d iHandlerMemType=%d\n", pVM->rem.s.iMMIOMemType, pVM->rem.s.iHandlerMemType));
/* stop ignoring. */
/*
* Register the saved state data unit.
*/
if (RT_FAILURE(rc))
return rc;
/*
* Debugger commands.
*/
static bool fRegisteredCmds = false;
if (!fRegisteredCmds)
{
if (RT_SUCCESS(rc))
fRegisteredCmds = true;
}
#endif
#ifdef VBOX_WITH_STATISTICS
/*
* Statistics.
*/
STAM_REG(pVM, &gStatExecuteSingleInstr, STAMTYPE_PROFILE, "/PROF/REM/SingleInstr",STAMUNIT_TICKS_PER_CALL, "Profiling single instruction emulation.");
STAM_REG(pVM, &gStatCompilationQEmu, STAMTYPE_PROFILE, "/PROF/REM/Compile", STAMUNIT_TICKS_PER_CALL, "Profiling QEmu compilation.");
STAM_REG(pVM, &gStatRunCodeQEmu, STAMTYPE_PROFILE, "/PROF/REM/Runcode", STAMUNIT_TICKS_PER_CALL, "Profiling QEmu code execution.");
STAM_REG(pVM, &gStatTotalTimeQEmu, STAMTYPE_PROFILE, "/PROF/REM/Emulate", STAMUNIT_TICKS_PER_CALL, "Profiling code emulation.");
STAM_REG(pVM, &gStatTimers, STAMTYPE_PROFILE, "/PROF/REM/Timers", STAMUNIT_TICKS_PER_CALL, "Profiling timer scheduling.");
STAM_REG(pVM, &gStatTBLookup, STAMTYPE_PROFILE, "/PROF/REM/TBLookup", STAMUNIT_TICKS_PER_CALL, "Profiling timer scheduling.");
STAM_REG(pVM, &gStatIRQ, STAMTYPE_PROFILE, "/PROF/REM/IRQ", STAMUNIT_TICKS_PER_CALL, "Profiling timer scheduling.");
STAM_REG(pVM, &gStatRawCheck, STAMTYPE_PROFILE, "/PROF/REM/RawCheck", STAMUNIT_TICKS_PER_CALL, "Profiling timer scheduling.");
STAM_REG(pVM, &gStatMemRead, STAMTYPE_PROFILE, "/PROF/REM/MemRead", STAMUNIT_TICKS_PER_CALL, "Profiling memory access.");
STAM_REG(pVM, &gStatMemWrite, STAMTYPE_PROFILE, "/PROF/REM/MemWrite", STAMUNIT_TICKS_PER_CALL, "Profiling memory access.");
STAM_REG(pVM, &gStatHCVirt2GCPhys, STAMTYPE_PROFILE, "/PROF/REM/HCVirt2GCPhys", STAMUNIT_TICKS_PER_CALL, "Profiling memory convertion.");
STAM_REG(pVM, &gStatGCPhys2HCVirt, STAMTYPE_PROFILE, "/PROF/REM/GCPhys2HCVirt", STAMUNIT_TICKS_PER_CALL, "Profiling memory convertion.");
STAM_REG(pVM, &gStatCpuGetTSC, STAMTYPE_COUNTER, "/REM/CpuGetTSC", STAMUNIT_OCCURENCES, "cpu_get_tsc calls");
STAM_REG(pVM, &gStatRefuseTFInhibit, STAMTYPE_COUNTER, "/REM/Refuse/TFInibit", STAMUNIT_OCCURENCES, "Raw mode refused because of TF or irq inhibit");
STAM_REG(pVM, &gStatRefuseVM86, STAMTYPE_COUNTER, "/REM/Refuse/VM86", STAMUNIT_OCCURENCES, "Raw mode refused because of VM86");
STAM_REG(pVM, &gStatRefusePaging, STAMTYPE_COUNTER, "/REM/Refuse/Paging", STAMUNIT_OCCURENCES, "Raw mode refused because of disabled paging/pm");
STAM_REG(pVM, &gStatRefusePAE, STAMTYPE_COUNTER, "/REM/Refuse/PAE", STAMUNIT_OCCURENCES, "Raw mode refused because of PAE");
STAM_REG(pVM, &gStatRefuseIOPLNot0, STAMTYPE_COUNTER, "/REM/Refuse/IOPLNot0", STAMUNIT_OCCURENCES, "Raw mode refused because of IOPL != 0");
STAM_REG(pVM, &gStatRefuseIF0, STAMTYPE_COUNTER, "/REM/Refuse/IF0", STAMUNIT_OCCURENCES, "Raw mode refused because of IF=0");
STAM_REG(pVM, &gStatRefuseCode16, STAMTYPE_COUNTER, "/REM/Refuse/Code16", STAMUNIT_OCCURENCES, "Raw mode refused because of 16 bit code");
STAM_REG(pVM, &gStatRefuseWP0, STAMTYPE_COUNTER, "/REM/Refuse/WP0", STAMUNIT_OCCURENCES, "Raw mode refused because of WP=0");
STAM_REG(pVM, &gStatRefuseRing1or2, STAMTYPE_COUNTER, "/REM/Refuse/Ring1or2", STAMUNIT_OCCURENCES, "Raw mode refused because of ring 1/2 execution");
STAM_REG(pVM, &gStatRefuseCanExecute, STAMTYPE_COUNTER, "/REM/Refuse/CanExecuteRaw", STAMUNIT_OCCURENCES, "Raw mode refused because of cCanExecuteRaw");
STAM_REG(pVM, &gStatFlushTBs, STAMTYPE_COUNTER, "/REM/FlushTB", STAMUNIT_OCCURENCES, "Number of TB flushes");
STAM_REG(pVM, &gStatREMGDTChange, STAMTYPE_COUNTER, "/REM/Change/GDTBase", STAMUNIT_OCCURENCES, "GDT base changes");
STAM_REG(pVM, &gStatREMLDTRChange, STAMTYPE_COUNTER, "/REM/Change/LDTR", STAMUNIT_OCCURENCES, "LDTR changes");
STAM_REG(pVM, &gStatREMIDTChange, STAMTYPE_COUNTER, "/REM/Change/IDTBase", STAMUNIT_OCCURENCES, "IDT base changes");
STAM_REG(pVM, &gStatREMTRChange, STAMTYPE_COUNTER, "/REM/Change/TR", STAMUNIT_OCCURENCES, "TR selector changes");
STAM_REG(pVM, &gStatSelOutOfSync[0], STAMTYPE_COUNTER, "/REM/State/SelOutOfSync/ES", STAMUNIT_OCCURENCES, "ES out of sync");
STAM_REG(pVM, &gStatSelOutOfSync[1], STAMTYPE_COUNTER, "/REM/State/SelOutOfSync/CS", STAMUNIT_OCCURENCES, "CS out of sync");
STAM_REG(pVM, &gStatSelOutOfSync[2], STAMTYPE_COUNTER, "/REM/State/SelOutOfSync/SS", STAMUNIT_OCCURENCES, "SS out of sync");
STAM_REG(pVM, &gStatSelOutOfSync[3], STAMTYPE_COUNTER, "/REM/State/SelOutOfSync/DS", STAMUNIT_OCCURENCES, "DS out of sync");
STAM_REG(pVM, &gStatSelOutOfSync[4], STAMTYPE_COUNTER, "/REM/State/SelOutOfSync/FS", STAMUNIT_OCCURENCES, "FS out of sync");
STAM_REG(pVM, &gStatSelOutOfSync[5], STAMTYPE_COUNTER, "/REM/State/SelOutOfSync/GS", STAMUNIT_OCCURENCES, "GS out of sync");
STAM_REG(pVM, &gStatSelOutOfSyncStateBack[0], STAMTYPE_COUNTER, "/REM/StateBack/SelOutOfSync/ES", STAMUNIT_OCCURENCES, "ES out of sync");
STAM_REG(pVM, &gStatSelOutOfSyncStateBack[1], STAMTYPE_COUNTER, "/REM/StateBack/SelOutOfSync/CS", STAMUNIT_OCCURENCES, "CS out of sync");
STAM_REG(pVM, &gStatSelOutOfSyncStateBack[2], STAMTYPE_COUNTER, "/REM/StateBack/SelOutOfSync/SS", STAMUNIT_OCCURENCES, "SS out of sync");
STAM_REG(pVM, &gStatSelOutOfSyncStateBack[3], STAMTYPE_COUNTER, "/REM/StateBack/SelOutOfSync/DS", STAMUNIT_OCCURENCES, "DS out of sync");
STAM_REG(pVM, &gStatSelOutOfSyncStateBack[4], STAMTYPE_COUNTER, "/REM/StateBack/SelOutOfSync/FS", STAMUNIT_OCCURENCES, "FS out of sync");
STAM_REG(pVM, &gStatSelOutOfSyncStateBack[5], STAMTYPE_COUNTER, "/REM/StateBack/SelOutOfSync/GS", STAMUNIT_OCCURENCES, "GS out of sync");
#endif
#ifdef DEBUG_ALL_LOGGING
loglevel = ~0;
# ifdef DEBUG_TMP_LOGGING
# endif
#endif
return rc;
}
/**
* Terminates the REM.
*
* Termination means cleaning up and freeing all resources,
* the VM it self is at this point powered off or suspended.
*
* @returns VBox status code.
* @param pVM The VM to operate on.
*/
{
return VINF_SUCCESS;
}
/**
* The VM is being reset.
*
* For the REM component this means to call the cpu_reset() and
* reinitialize some state variables.
*
* @param pVM VM handle.
*/
{
/*
* Reset the REM cpu.
*/
/* Clear raw ring 0 init state */
/* Flush the TBs the next time we execute code here. */
}
/**
* Execute state save operation.
*
* @returns VBox status code.
* @param pVM VM Handle.
* @param pSSM SSM operation handle.
*/
{
/*
* Save the required CPU Env bits.
* (Not much because we're never in REM when doing the save.)
*/
LogFlow(("remR3Save:\n"));
/* Remember if we've entered raw mode (vital for ring 1 checks in e.g. iret emulation). */
}
/**
* Execute state load operation.
*
* @returns VBox status code.
* @param pVM VM Handle.
* @param pSSM SSM operation handle.
* @param u32Version Data layout version.
*/
{
int rc;
LogFlow(("remR3Load:\n"));
/*
* Validate version.
*/
if ( u32Version != REM_SAVED_STATE_VERSION
{
}
/*
* Do a reset to be on the safe side...
*/
/*
* Ignore all ignorable notifications.
* (Not doing this will cause serious trouble.)
*/
/*
* Load the required CPU Env bits.
* (Not much because we're never in REM when doing the save.)
*/
{
/* Redundant REM CPU state has to be loaded, but can be ignored. */
}
if (RT_FAILURE(rc))
return rc;
if (u32Sep != ~0U)
{
}
/* Remember if we've entered raw mode (vital for ring 1 checks in e.g. iret emulation). */
if (fRawRing0)
{
unsigned i;
/*
* Load the REM stuff.
*/
if (RT_FAILURE(rc))
return rc;
{
}
for (i = 0; i < pRem->cInvalidatedPages; i++)
}
if (RT_FAILURE(rc))
return rc;
/* check the terminator. */
if (RT_FAILURE(rc))
return rc;
if (u32Sep != ~0U)
{
}
/*
* Get the CPUID features.
*/
CPUMGetGuestCpuId(pVM, 1, &u32Dummy, &u32Dummy, &pVM->rem.s.Env.cpuid_ext_features, &pVM->rem.s.Env.cpuid_features);
CPUMGetGuestCpuId(pVM, 0x80000001, &u32Dummy, &u32Dummy, &u32Dummy, &pVM->rem.s.Env.cpuid_ext2_features);
/*
* Sync the Load Flush the TLB
*/
/*
* Stop ignoring ignornable notifications.
*/
/*
* Sync the whole CPU state when executing code in the recompiler.
*/
return VINF_SUCCESS;
}
#define LOG_GROUP LOG_GROUP_REM_RUN
/**
* Single steps an instruction in recompiled mode.
*
* Before calling this function the REM state needs to be in sync with
* the VM. Call REMR3State() to perform the sync. It's only necessary
* (and permitted) to sync at the first call to REMR3Step()/REMR3Run()
* and after calling REMR3StateBack().
*
* @returns VBox status code.
*
* @param pVM VM Handle.
*/
{
int rc, interrupt_request;
bool fBp;
/*
* Lock the REM - we don't wanna have anyone interrupting us
* while stepping - and enabled single stepping. We also ignore
* pending interrupts and suchlike.
*/
Assert(!(interrupt_request & ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXIT | CPU_INTERRUPT_EXITTB | CPU_INTERRUPT_TIMER | CPU_INTERRUPT_EXTERNAL_HARD | CPU_INTERRUPT_EXTERNAL_EXIT | CPU_INTERRUPT_EXTERNAL_TIMER)));
/*
* If we're standing at a breakpoint, that have to be disabled before we start stepping.
*/
/*
* Execute and handle the return code.
* We execute without enabling the cpu tick, so on success we'll
* just flip it on and off to make sure it moves
*/
if (rc == EXCP_DEBUG)
{
}
else
{
switch (rc)
{
case EXCP_HLT:
case EXCP_RC:
break;
default:
break;
}
}
/*
* Restore the stuff we changed to prevent interruption.
* Unlock the REM.
*/
if (fBp)
{
}
return rc;
}
/**
* Set a breakpoint using the REM facilities.
*
* @returns VBox status code.
* @param pVM The VM handle.
* @param Address The breakpoint address.
* @thread The emulation thread.
*/
{
{
return VINF_SUCCESS;
}
return VERR_REM_NO_MORE_BP_SLOTS;
}
/**
* Clears a breakpoint set by REMR3BreakpointSet().
*
* @returns VBox status code.
* @param pVM The VM handle.
* @param Address The breakpoint address.
* @thread The emulation thread.
*/
{
{
return VINF_SUCCESS;
}
return VERR_REM_BP_NOT_FOUND;
}
/**
* Emulate an instruction.
*
* This function executes one instruction without letting anyone
* interrupt it. This is intended for being called while being in
* raw mode and thus will take care of all the state syncing between
* REM and the rest.
*
* @returns VBox status code.
* @param pVM VM handle.
*/
{
bool fFlushTBs;
/* Make sure this flag is set; we might never execute remR3CanExecuteRaw in the AMD-V case.
* CPU_RAW_HWACC makes sure we never execute interrupt handlers in the recompiler.
*/
if (HWACCMIsEnabled(pVM))
/* Skip the TB flush as that's rather expensive and not necessary for single instruction emulation. */
/*
* Sync the state and enable single instruction / single stepping.
*/
if (RT_SUCCESS(rc))
{
Assert(!(interrupt_request & ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXIT | CPU_INTERRUPT_EXITTB | CPU_INTERRUPT_TIMER | CPU_INTERRUPT_EXTERNAL_HARD | CPU_INTERRUPT_EXTERNAL_EXIT | CPU_INTERRUPT_EXTERNAL_TIMER)));
/*
* Now we set the execute single instruction flag and enter the cpu_exec loop.
*/
switch (rc)
{
/*
* Executed without anything out of the way happening.
*/
case EXCP_SINGLE_INSTR:
Log2(("REMR3EmulateInstruction: cpu_exec -> EXCP_SINGLE_INSTR\n"));
break;
/*
* If we take a trap or start servicing a pending interrupt, we might end up here.
* (Timer thread or some other thread wishing EMT's attention.)
*/
case EXCP_INTERRUPT:
Log2(("REMR3EmulateInstruction: cpu_exec -> EXCP_INTERRUPT\n"));
break;
/*
* Single step, we assume!
* If there was a breakpoint there we're fucked now.
*/
case EXCP_DEBUG:
{
/* breakpoint or single step? */
int iBP;
{
break;
}
Log2(("REMR3EmulateInstruction: cpu_exec -> EXCP_DEBUG rc=%Rrc iBP=%d GCPtrPC=%RGv\n", rc, iBP, GCPtrPC));
break;
}
/*
* hlt instruction.
*/
case EXCP_HLT:
Log2(("REMR3EmulateInstruction: cpu_exec -> EXCP_HLT\n"));
rc = VINF_EM_HALT;
break;
/*
* The VM has halted.
*/
case EXCP_HALTED:
Log2(("REMR3EmulateInstruction: cpu_exec -> EXCP_HALTED\n"));
rc = VINF_EM_HALT;
break;
/*
* Switch to RAW-mode.
*/
case EXCP_EXECUTE_RAW:
Log2(("REMR3EmulateInstruction: cpu_exec -> EXCP_EXECUTE_RAW\n"));
break;
/*
* Switch to hardware accelerated RAW-mode.
*/
case EXCP_EXECUTE_HWACC:
Log2(("REMR3EmulateInstruction: cpu_exec -> EXCP_EXECUTE_HWACC\n"));
break;
/*
* An EM RC was raised (VMR3Reset/Suspend/PowerOff/some-fatal-error).
*/
case EXCP_RC:
Log2(("REMR3EmulateInstruction: cpu_exec -> EXCP_RC\n"));
break;
/*
* Figure out the rest when they arrive....
*/
default:
break;
}
/*
* Switch back the state.
*/
}
Log2(("REMR3EmulateInstruction: returns %Rrc (cs:eip=%04x:%RGv)\n",
return rc;
}
/**
* Runs code in recompiled mode.
*
* Before calling this function the REM state needs to be in sync with
* the VM. Call REMR3State() to perform the sync. It's only necessary
* (and permitted) to sync at the first call to REMR3Step()/REMR3Run()
* and after calling REMR3StateBack().
*
* @returns VBox status code.
*
* @param pVM VM Handle.
*/
{
int rc;
Log2(("REMR3Run: (cs:eip=%04x:%RGv)\n", pVM->rem.s.Env.segs[R_CS].selector, (RTGCPTR)pVM->rem.s.Env.eip));
switch (rc)
{
/*
* This happens when the execution was interrupted
* by an external event, like pending timers.
*/
case EXCP_INTERRUPT:
Log2(("REMR3Run: cpu_exec -> EXCP_INTERRUPT\n"));
rc = VINF_SUCCESS;
break;
/*
* hlt instruction.
*/
case EXCP_HLT:
Log2(("REMR3Run: cpu_exec -> EXCP_HLT\n"));
rc = VINF_EM_HALT;
break;
/*
* The VM has halted.
*/
case EXCP_HALTED:
Log2(("REMR3Run: cpu_exec -> EXCP_HALTED\n"));
rc = VINF_EM_HALT;
break;
/*
* Breakpoint/single step.
*/
case EXCP_DEBUG:
{
#if 0//def DEBUG_bird
static int iBP = 0;
switch (iBP)
{
case 0:
//pVM->rem.s.Env.interrupt_request = 0;
//pVM->rem.s.Env.exception_index = -1;
//g_fInterruptDisabled = 1;
rc = VINF_SUCCESS;
asm("int3");
break;
default:
asm("int3");
break;
}
iBP++;
#else
/* breakpoint or single step? */
int iBP;
{
break;
}
#endif
break;
}
/*
* Switch to RAW-mode.
*/
case EXCP_EXECUTE_RAW:
Log2(("REMR3Run: cpu_exec -> EXCP_EXECUTE_RAW\n"));
break;
/*
* Switch to hardware accelerated RAW-mode.
*/
case EXCP_EXECUTE_HWACC:
Log2(("REMR3Run: cpu_exec -> EXCP_EXECUTE_HWACC\n"));
break;
/** @todo missing VBOX_WITH_VMI/EXECP_PARAV_CALL */
/*
* An EM RC was raised (VMR3Reset/Suspend/PowerOff/some-fatal-error).
*/
case EXCP_RC:
break;
/*
* Figure out the rest when they arrive....
*/
default:
rc = VINF_SUCCESS;
break;
}
Log2(("REMR3Run: returns %Rrc (cs:eip=%04x:%RGv)\n", rc, pVM->rem.s.Env.segs[R_CS].selector, (RTGCPTR)pVM->rem.s.Env.eip));
return rc;
}
/**
* Check if the cpu state is suitable for Raw execution.
*
* @returns boolean
* @param env The CPU env struct.
* @param eip The EIP to check this for (might differ from env->eip).
* @param fFlags hflags OR'ed with IOPL, TF and VM from eflags.
* @param piException Stores EXCP_EXECUTE_RAW/HWACC in case raw mode is supported in this context
*
* @remark This function must be kept in perfect sync with the scheduler in EM.cpp!
*/
{
/* !!! THIS MUST BE IN SYNC WITH emR3Reschedule !!! */
/* !!! THIS MUST BE IN SYNC WITH emR3Reschedule !!! */
/* !!! THIS MUST BE IN SYNC WITH emR3Reschedule !!! */
/* Update counter. */
{
/*
* Create partial context for HWACCMR3CanExecuteGuest
*/
#ifdef LOG_ENABLED
#endif
/* Hardware accelerated raw-mode:
*
* Typically only 32-bits protected mode, with paging enabled, code is allowed here.
*/
{
return true;
}
return false;
}
/*
* Here we only support 16 & 32 bits protected mode ring 3 code that has no IO privileges
* or 32 bits protected mode ring 0 code
*
* The tests are ordered by the likelyhood of being true during normal execution.
*/
{
return false;
}
#ifndef VBOX_RAW_V86
Log2(("raw mode refused: VM_MASK\n"));
return false;
}
#endif
{
#ifndef DEBUG_bird
Log2(("raw mode refused: CPU_EMULATE_SINGLE_INSTR\n"));
#endif
return false;
}
if (env->singlestep_enabled)
{
//Log2(("raw mode refused: Single step\n"));
return false;
}
if (env->nb_breakpoints > 0)
{
//Log2(("raw mode refused: Breakpoints\n"));
return false;
}
{
//Log2(("raw mode refused: %s%s%s\n", (u32CR0 & X86_CR0_PG) ? "" : " !PG", (u32CR0 & X86_CR0_PE) ? "" : " !PE", (u32CR0 & X86_CR0_AM) ? "" : " !AM"));
return false;
}
{
{
return false;
}
}
{
return false;
{
Log2(("raw mode refused: IF (RawR3)\n"));
return false;
}
{
Log2(("raw mode refused: CR0.WP + RawR0\n"));
return false;
}
}
else
{
return false;
// Let's start with pure 32 bits ring 0 code first
{
return false;
}
// Only R0
{
return false;
}
if (!(u32CR0 & CR0_WP_MASK))
{
Log2(("raw r0 mode refused: CR0.WP=0!\n"));
return false;
}
{
Log2(("raw r0 mode forced: patch code\n"));
return true;
}
#if !defined(VBOX_ALLOW_IF0) && !defined(VBOX_RUN_INTERRUPT_GATE_HANDLERS)
{
////Log2(("R0: IF=0 VIF=%d %08X\n", eip, *env->pVMeflags));
//Log2(("RR0: Interrupts turned off; fall back to emulation\n"));
return false;
}
#endif
}
/*
* Don't reschedule the first time we're called, because there might be
* special reasons why we're here that is not covered by the above checks.
*/
{
Log2(("raw mode refused: first scheduling\n"));
return false;
}
return true;
}
/**
* Fetches a code byte.
*
* @returns Success indicator (bool) for ease of use.
* @param env The CPU environment structure.
* @param GCPtrInstr Where to fetch code.
* @param pu8Byte Where to store the byte on success
*/
{
if (RT_SUCCESS(rc))
return true;
return false;
}
/**
*
* (invlpg instruction; tlb_flush_page)
*
* @param env Pointer to cpu environment.
*/
{
int rc;
/*
* When we're replaying invlpg instructions or restoring a saved
* state we disable this path.
*/
return;
//RAWEx_ProfileStop(env, STATS_QEMU_TOTAL);
/*
* Update the control registers before calling PGMFlushPage.
*/
/*
* Let PGM do the rest.
*/
if (RT_FAILURE(rc))
{
}
//RAWEx_ProfileStart(env, STATS_QEMU_TOTAL);
}
#ifndef REM_PHYS_ADDR_IN_TLB
{
void *pv;
int rc;
/* Address must be aligned enough to fiddle with lower bits */
|| rc == VERR_PGM_PHYS_TLB_UNASSIGNED);
if (RT_FAILURE(rc))
return (void *)1;
if (rc == VINF_PGM_PHYS_TLB_CATCH_WRITE)
return pv;
}
{
int rc;
return (target_ulong)rv;
}
#endif
/**
* Called from tlb_protect_code in order to write monitor a code page.
*
* @param env Pointer to the CPU environment.
* @param GCPtr Code page to monitor
*/
{
#endif
}
/**
* Called from tlb_unprotect_code in order to clear write monitoring for a code page.
*
* @param env Pointer to the CPU environment.
* @param GCPtr Code page to monitor
*/
{
#endif
}
/**
* Called when the CPU is initialized, any of the CRx registers are changed or
* when the A20 line is modified.
*
* @param env Pointer to the CPU environment.
* @param fGlobal Set if the flush is global.
*/
{
/*
* When we're replaying invlpg instructions or restoring a saved
* state we disable this path.
*/
return;
/*
* The caller doesn't check cr4, so we have to do that for ourselves.
*/
fGlobal = true;
Log(("remR3FlushTLB: CR0=%08RX64 CR3=%08RX64 CR4=%08RX64 %s\n", (uint64_t)env->cr[0], (uint64_t)env->cr[3], (uint64_t)env->cr[4], fGlobal ? " global" : ""));
/*
* Update the control registers before calling PGMR3FlushTLB.
*/
/*
* Let PGM do the rest.
*/
}
/**
* Called when any of the cr0, cr4 or efer registers is updated.
*
* @param env Pointer to the CPU environment.
*/
{
int rc;
/*
* When we're replaying loads or restoring a saved
* state this path is disabled.
*/
return;
/*
* Update the control registers before calling PGMChangeMode()
* as it may need to map whatever cr3 is pointing to.
*/
#ifdef TARGET_X86_64
if (rc != VINF_SUCCESS)
cpu_abort(env, "PGMChangeMode(, %RX64, %RX64, %RX64) -> %Rrc\n", env->cr[0], env->cr[4], env->efer, rc);
#else
if (rc != VINF_SUCCESS)
#endif
}
/**
* Called from compiled code to run dma.
*
* @param env Pointer to the CPU environment.
*/
{
}
/**
* Called from compiled code to schedule pending timers in VMM
*
* @param env Pointer to the CPU environment.
*/
{
LogFlow(("remR3TimersRun:\n"));
}
/**
* Record trap occurance
*
* @returns VBox status code
* @param env Pointer to the CPU environment.
* @param uTrap Trap nr
* @param uErrorCode Error code
* @param pvNextEIP Next EIP
*/
{
#ifdef VBOX_WITH_STATISTICS
#endif
#ifdef VBOX_WITH_STATISTICS
if (uTrap < 255)
{
if (!s_aRegisters[uTrap])
{
char szStatName[64];
s_aRegisters[uTrap] = true;
STAM_REG(env->pVM, &s_aStatTrap[uTrap], STAMTYPE_COUNTER, szStatName, STAMUNIT_OCCURENCES, "Trap stats.");
}
}
#endif
Log(("remR3NotifyTrap: uTrap=%x error=%x next_eip=%RGv eip=%RGv cr2=%RGv\n", uTrap, uErrorCode, pvNextEIP, (RTGCPTR)env->eip, (RTGCPTR)env->cr[2]));
if( uTrap < 0x20
{
#ifdef DEBUG
#endif
{
LogRel(("VERR_REM_TOO_MANY_TRAPS -> uTrap=%x error=%x next_eip=%RGv eip=%RGv cr2=%RGv\n", uTrap, uErrorCode, pvNextEIP, (RTGCPTR)env->eip, (RTGCPTR)env->cr[2]));
return VERR_REM_TOO_MANY_TRAPS;
}
if(pVM->rem.s.uPendingException != uTrap || pVM->rem.s.uPendingExcptEIP != env->eip || pVM->rem.s.uPendingExcptCR2 != env->cr[2])
}
else
{
}
return VINF_SUCCESS;
}
/*
* Clear current active trap
*
* @param pVM VM Handle.
*/
{
}
/*
* Record previous call instruction addresses
*
* @param env Pointer to the CPU environment.
*/
{
}
/**
* Syncs the internal REM state with the VM.
*
* This must be called before REMR3Run() is invoked whenever when the REM
* state is not up to date. Calling it several times in a row is not
* permitted.
*
* @returns VBox status code.
*
* @param pVM VM Handle.
* @param fFlushTBs Flush all translation blocks before executing code
*
* @remark The caller has to check for important FFs before calling REMR3Run. REMR3State will
* no do this since the majority of the callers don't want any unnecessary of events
* pending that would immediatly interrupt execution.
*/
{
register unsigned fFlags;
bool fHiddenSelRegsValid;
unsigned i;
int rc;
Log2(("REMR3State:\n"));
/*
* If we have to flush TBs, do that immediately.
*/
{
}
/*
* Copy the registers which require no special handling.
*/
#ifdef TARGET_X86_64
/* Note that the high dwords of 64 bits registers are undefined in 32 bits mode and are undefined after a mode change. */
#else
#endif
/** @todo we could probably benefit from using a CPUM_CHANGED_DRx flag too! */
for (i=0;i<8;i++)
/*
* Clear the halted hidden flag (the interrupt waking up the CPU can
* have been dispatched in raw mode).
*/
/*
* Replay invlpg?
*/
{
RTUINT i;
{
}
}
/* Replay notification changes? */
/* Update MSRs; before CRx registers! */
#ifdef TARGET_X86_64
/* Update the internal long mode activate flag according to the new EFER value. */
else
#endif
/*
* Registers which are rarely changed and require special handling / order when changed.
*/
{
{
}
/* CR4 before CR0! */
if (fFlags & CPUM_CHANGED_CR4)
{
}
if (fFlags & CPUM_CHANGED_CR0)
{
}
if (fFlags & CPUM_CHANGED_CR3)
{
}
if (fFlags & CPUM_CHANGED_GDTR)
{
}
if (fFlags & CPUM_CHANGED_IDTR)
{
}
if (fFlags & CPUM_CHANGED_SYSENTER_MSR)
{
}
if (fFlags & CPUM_CHANGED_LDTR)
{
if (fHiddenSelRegsValid)
{
}
else
}
if (fFlags & CPUM_CHANGED_CPUID)
{
/*
* Get the CPUID features.
*/
CPUMGetGuestCpuId(pVM, 1, &u32Dummy, &u32Dummy, &pVM->rem.s.Env.cpuid_ext_features, &pVM->rem.s.Env.cpuid_features);
CPUMGetGuestCpuId(pVM, 0x80000001, &u32Dummy, &u32Dummy, &u32Dummy, &pVM->rem.s.Env.cpuid_ext2_features);
}
/* Sync FPU state after CR4, CPUID and EFER (!). */
if (fFlags & CPUM_CHANGED_FPU_REM)
}
/*
* Sync TR unconditionally to make life simpler.
*/
/* Note! do_interrupt will fault if the busy flag is still set... */
/*
* Update selector registers.
* This must be done *after* we've synced gdt, ldt and crX registers
* saved state which takes a quick dip into rawmode for instance.
*/
/*
* Stack; Note first check this one as the CPL might have changed. The
* wrong CPL can cause QEmu to raise an exception in sync_seg!!
*/
if (fHiddenSelRegsValid)
{
/* The hidden selector registers are valid in the CPU context. */
/** @note QEmu saves the 2nd dword of the descriptor; we should convert the attribute word back! */
/* Set current CPL */
cpu_x86_load_seg_cache(&pVM->rem.s.Env, R_CS, pCtx->cs, pCtx->csHid.u64Base, pCtx->csHid.u32Limit, (pCtx->csHid.Attr.u << 8) & 0xFFFFFF);
cpu_x86_load_seg_cache(&pVM->rem.s.Env, R_SS, pCtx->ss, pCtx->ssHid.u64Base, pCtx->ssHid.u32Limit, (pCtx->ssHid.Attr.u << 8) & 0xFFFFFF);
cpu_x86_load_seg_cache(&pVM->rem.s.Env, R_DS, pCtx->ds, pCtx->dsHid.u64Base, pCtx->dsHid.u32Limit, (pCtx->dsHid.Attr.u << 8) & 0xFFFFFF);
cpu_x86_load_seg_cache(&pVM->rem.s.Env, R_ES, pCtx->es, pCtx->esHid.u64Base, pCtx->esHid.u32Limit, (pCtx->esHid.Attr.u << 8) & 0xFFFFFF);
cpu_x86_load_seg_cache(&pVM->rem.s.Env, R_FS, pCtx->fs, pCtx->fsHid.u64Base, pCtx->fsHid.u32Limit, (pCtx->fsHid.Attr.u << 8) & 0xFFFFFF);
cpu_x86_load_seg_cache(&pVM->rem.s.Env, R_GS, pCtx->gs, pCtx->gsHid.u64Base, pCtx->gsHid.u32Limit, (pCtx->gsHid.Attr.u << 8) & 0xFFFFFF);
}
else
{
/* In 'normal' raw mode we don't have access to the hidden selector registers. */
{
Log2(("REMR3State: SS changed from %04x to %04x!\n", pVM->rem.s.Env.segs[R_SS].selector, pCtx->ss));
#ifdef VBOX_WITH_STATISTICS
{
}
#endif
}
else
{
Log2(("REMR3State: ES changed from %04x to %04x!\n", pVM->rem.s.Env.segs[R_ES].selector, pCtx->es));
#ifdef VBOX_WITH_STATISTICS
{
}
#endif
}
else
{
Log2(("REMR3State: CS changed from %04x to %04x!\n", pVM->rem.s.Env.segs[R_CS].selector, pCtx->cs));
#ifdef VBOX_WITH_STATISTICS
{
}
#endif
}
else
{
Log2(("REMR3State: DS changed from %04x to %04x!\n", pVM->rem.s.Env.segs[R_DS].selector, pCtx->ds));
#ifdef VBOX_WITH_STATISTICS
{
}
#endif
}
else
/** @todo need to find a way to communicate potential GDT/LDT changes and thread switches. The selector might
{
Log2(("REMR3State: FS changed from %04x to %04x!\n", pVM->rem.s.Env.segs[R_FS].selector, pCtx->fs));
#ifdef VBOX_WITH_STATISTICS
{
}
#endif
}
else
{
Log2(("REMR3State: GS changed from %04x to %04x!\n", pVM->rem.s.Env.segs[R_GS].selector, pCtx->gs));
#ifdef VBOX_WITH_STATISTICS
{
}
#endif
}
else
}
/*
* Check for traps.
*/
if (RT_SUCCESS(rc))
{
#ifdef DEBUG
if (u8TrapNo == 0x80)
{
}
#endif
if (enmType != TRPM_SOFTWARE_INT)
{
}
else
{
/*
* The there are two 1 byte opcodes and one 2 byte opcode for software interrupts.
* We ASSUME that there are no prefixes and sets the default to 2 byte, and checks
* for int03 and into.
*/
/* int 3 may be generated by one-byte 0xcc */
if (u8TrapNo == 3)
{
}
/* int 4 may be generated by one-byte 0xce */
else if (u8TrapNo == 4)
{
}
}
/* get error code and cr2 if needed. */
switch (u8TrapNo)
{
case 0x0e:
/* fallthru */
case 0x0a: case 0x0b: case 0x0c: case 0x0d:
break;
case 0x11: case 0x08:
default:
break;
}
/*
* We can now reset the active trap since the recompiler is gonna have a go at it.
*/
Log2(("REMR3State: trap=%02x errcd=%RGv cr2=%RGv nexteip=%RGv%s\n", pVM->rem.s.Env.exception_index, (RTGCPTR)pVM->rem.s.Env.error_code,
(RTGCPTR)pVM->rem.s.Env.cr[2], (RTGCPTR)pVM->rem.s.Env.exception_next_eip, pVM->rem.s.Env.exception_is_int ? " software" : ""));
}
/*
* Clear old interrupt request flags; Check for pending hardware interrupts.
* (See @remark for why we don't check for other FFs.)
*/
pVM->rem.s.Env.interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXIT | CPU_INTERRUPT_EXITTB | CPU_INTERRUPT_TIMER);
/*
* We're now in REM mode.
*/
Log2(("REMR3State: returns VINF_SUCCESS\n"));
return VINF_SUCCESS;
}
/**
* Syncs back changes in the REM state to the the VM state.
*
* This must be called after invoking REMR3Run().
* Calling it several times in a row is not permitted.
*
* @returns VBox status code.
*
* @param pVM VM Handle.
*/
{
unsigned i;
Log2(("REMR3StateBack:\n"));
/*
* Copy back the registers.
* This is done in the order they are declared in the CPUMCTX structure.
*/
/** @todo FOP */
/** @todo FPUIP */
/** @todo CS */
/** @todo FPUDP */
/** @todo DS */
//// dprintf2(("FPU state CW=%04X TT=%04X SW=%04X (%04X)\n", env->fpuc, env->fpstt, env->fpus, pVMCtx->fpu.FSW));
#ifdef TARGET_X86_64
/* Note that the high dwords of 64 bits registers are undefined in 32 bits mode and are undefined after a mode change. */
#else
#endif
#ifdef VBOX_WITH_STATISTICS
{
}
{
}
{
}
{
}
{
}
{
}
#endif
#ifdef TARGET_X86_64
#else
#endif
for (i = 0; i < 8; i++)
{
}
{
}
{
}
: 0) )
{
Log(("REM: TR changed! %#x{%#llx,%#x,%#x} -> %#x{%llx,%#x,%#x}\n",
(pVM->rem.s.Env.tr.flags >> 8) & 0xF0FF ? (pVM->rem.s.Env.tr.flags | DESC_TSS_BUSY_MASK) >> 8 : 0));
}
/** @todo These values could still be out of sync! */
/* Note! QEmu saves the 2nd dword of the descriptor; we should store the attribute word only! */
/* Sysenter MSR */
/* System MSRs. */
#ifdef TARGET_X86_64
#endif
/*
* Check for traps.
*/
{
int rc;
Log(("REMR3StateBack: Pending trap %x %d\n", pVM->rem.s.Env.exception_index, pVM->rem.s.Env.exception_is_int));
rc = TRPMAssertTrap(pVM, pVM->rem.s.Env.exception_index, (pVM->rem.s.Env.exception_is_int) ? TRPM_SOFTWARE_INT : TRPM_HARDWARE_INT);
{
case 0x0e:
/* fallthru */
case 0x0a: case 0x0b: case 0x0c: case 0x0d:
case 0x11: case 0x08: /* 0 */
break;
}
}
/*
* We're not longer in REM mode.
*/
Log2(("REMR3StateBack: returns VINF_SUCCESS\n"));
return VINF_SUCCESS;
}
/**
* This is called by the disassembler when it wants to update the cpu state
* before for instance doing a register dump.
*/
{
unsigned i;
/*
* Copy back the registers.
* This is done in the order they are declared in the CPUMCTX structure.
*/
/** @todo FOP */
/** @todo FPUIP */
/** @todo CS */
/** @todo FPUDP */
/** @todo DS */
/** @todo Fix MXCSR support in QEMU so we don't overwrite MXCSR with 0 when we shouldn't! */
//// dprintf2(("FPU state CW=%04X TT=%04X SW=%04X (%04X)\n", env->fpuc, env->fpstt, env->fpus, pVMCtx->fpu.FSW));
#ifdef TARGET_X86_64
#else
#endif
#ifdef TARGET_X86_64
#else
#endif
for (i = 0; i < 8; i++)
{
}
{
}
{
}
: 0) )
{
Log(("REM: TR changed! %#x{%#llx,%#x,%#x} -> %#x{%llx,%#x,%#x}\n",
(pVM->rem.s.Env.tr.flags >> 8) & 0xF0FF ? (pVM->rem.s.Env.tr.flags | DESC_TSS_BUSY_MASK) >> 8 : 0));
}
/** @todo These values could still be out of sync! */
/** @note QEmu saves the 2nd dword of the descriptor; we should store the attribute word only! */
/* Sysenter MSR */
/* System MSRs. */
#ifdef TARGET_X86_64
#endif
}
/**
* Update the VMM state information if we're currently in REM.
*
* This method is used by the DBGF and PDMDevice when there is any uncertainty of whether
* we're currently executing in REM and the VMM state is invalid. This method will of
* course check that we're executing in REM before syncing any data over to the VMM.
*
* @param pVM The VM handle.
*/
{
}
#define LOG_GROUP LOG_GROUP_REM
/**
* Notify the recompiler about Address Gate 20 state change.
*
* This notification is required since A20 gate changes are
* initialized from a device driver and the VM might just as
* well be in REM mode as in RAW mode.
*
* @param pVM VM handle.
* @param fEnable True if the gate should be enabled.
* False if the gate should be disabled.
*/
{
bool fSaved;
}
/**
* Replays the invalidated recorded pages.
* Called in response to VERR_REM_FLUSHED_PAGES_OVERFLOW from the RAW execution loop.
*
* @param pVM VM handle.
*/
{
RTUINT i;
/*
* Sync the required registers.
*/
/*
* Replay the flushes.
*/
{
}
}
/**
* Replays the handler notification changes
* Called in response to VM_FF_REM_HANDLER_NOTIFY from the RAW execution loop.
*
* @param pVM VM handle.
*/
{
/*
* Replay the flushes.
*/
RTUINT i;
LogFlow(("REMR3ReplayInvalidatedPages:\n"));
for (i = 0; i < c; i++)
{
{
break;
break;
break;
default:
break;
}
}
}
/**
* Notify REM about changed code page.
*
* @returns VBox status code.
* @param pVM VM handle.
* @param pvCodePage Code page address
*/
{
int rc;
/*
* Get the physical page address.
*/
if (rc == VINF_SUCCESS)
{
/*
* Sync the required registers and flush the whole page.
* (Easier to do the whole page than notifying it about each physical
* byte that was changed.
*/
}
#endif
return VINF_SUCCESS;
}
/**
* Notification about a successful MMR3PhysRegister() call.
*
* @param pVM VM handle.
* @param GCPhys The physical address the RAM.
* @param cb Size of the memory.
* @param fFlags Flags of the MM_RAM_FLAGS_* defines.
*/
{
int rc;
/*
* Validate input - we trust the caller.
*/
/*
* Base ram?
*/
if (!GCPhys)
{
phys_ram_size = cb;
#ifndef VBOX_STRICT
AssertReleaseMsg(phys_ram_dirty, ("failed to allocate %d bytes of dirty bytes\n", phys_ram_dirty_size));
#else /* VBOX_STRICT: allocate a full map and make the out of bounds pages invalid. */
AssertReleaseMsg(phys_ram_dirty, ("failed to allocate %d bytes of dirty bytes\n", _4G >> PAGE_SHIFT));
#endif
}
/*
* Register the ram.
*/
#ifdef VBOX_WITH_NEW_PHYS_CODE
if (fFlags & MM_RAM_FLAGS_RESERVED)
else
#else
if (!GCPhys)
else
{
if (fFlags & MM_RAM_FLAGS_RESERVED)
else
}
#endif
}
#ifndef VBOX_WITH_NEW_PHYS_CODE
/**
* Notification about a successful PGMR3PhysRegisterChunk() call.
*
* @param pVM VM handle.
* @param GCPhys The physical address the RAM.
* @param cb Size of the memory.
* @param pvRam The HC address of the RAM.
* @param fFlags Flags of the MM_RAM_FLAGS_* defines.
*/
REMR3DECL(void) REMR3NotifyPhysRamChunkRegister(PVM pVM, RTGCPHYS GCPhys, RTUINT cb, RTHCUINTPTR pvRam, unsigned fFlags)
{
Log(("REMR3NotifyPhysRamChunkRegister: GCPhys=%RGp cb=%d pvRam=%p fFlags=%d\n", GCPhys, cb, pvRam, fFlags));
/*
* Validate input - we trust the caller.
*/
}
/**
* Grows dynamically allocated guest RAM.
* Will raise a fatal error if the operation fails.
*
* @param physaddr The physical address.
*/
{
int rc;
if (RT_SUCCESS(rc))
return;
}
#endif /* !VBOX_WITH_NEW_PHYS_CODE */
/**
* Notification about a successful MMR3PhysRomRegister() call.
*
* @param pVM VM handle.
* @param GCPhys The physical address of the ROM.
* @param cb The size of the ROM.
* @param pvCopy Pointer to the ROM copy.
* @param fShadow Whether it's currently writable shadow ROM or normal readonly ROM.
* This function will be called when ever the protection of the
* shadow ROM changes (at reset and end of POST).
*/
REMR3DECL(void) REMR3NotifyPhysRomRegister(PVM pVM, RTGCPHYS GCPhys, RTUINT cb, void *pvCopy, bool fShadow)
{
Log(("REMR3NotifyPhysRomRegister: GCPhys=%RGp cb=%d pvCopy=%p fShadow=%RTbool\n", GCPhys, cb, pvCopy, fShadow));
/*
* Validate input - we trust the caller.
*/
/*
* Register the rom.
*/
}
/**
* Notification about a successful memory deregistration or reservation.
*
* @param pVM VM Handle.
* @param GCPhys Start physical address.
* @param cb The size of the range.
* @todo Rename to REMR3NotifyPhysRamDeregister (for MMIO2) as we won't
* reserve any memory soon.
*/
{
/*
* Validate input - we trust the caller.
*/
/*
* Unassigning the memory.
*/
}
/**
* Notification about a successful PGMR3HandlerPhysicalRegister() call.
*
* @param pVM VM Handle.
* @param enmType Handler type.
* @param GCPhys Handler range address.
* @param cb Size of the handler range.
* @param fHasHCHandler Set if the handler has a HC callback function.
*
* @remark MMR3PhysRomRegister assumes that this function will not apply the
* Handler memory type to memory which has no HC handler.
*/
REMR3DECL(void) REMR3NotifyHandlerPhysicalRegister(PVM pVM, PGMPHYSHANDLERTYPE enmType, RTGCPHYS GCPhys, RTGCPHYS cb, bool fHasHCHandler)
{
Log(("REMR3NotifyHandlerPhysicalRegister: enmType=%d GCPhys=%RGp cb=%RGp fHasHCHandler=%d\n",
if (enmType == PGMPHYSHANDLERTYPE_MMIO)
else if (fHasHCHandler)
}
/**
* Notification about a successful PGMR3HandlerPhysicalDeregister() operation.
*
* @param pVM VM Handle.
* @param enmType Handler type.
* @param GCPhys Handler range address.
* @param cb Size of the handler range.
* @param fHasHCHandler Set if the handler has a HC callback function.
* @param fRestoreAsRAM Whether the to restore it as normal RAM or as unassigned memory.
*/
REMR3DECL(void) REMR3NotifyHandlerPhysicalDeregister(PVM pVM, PGMPHYSHANDLERTYPE enmType, RTGCPHYS GCPhys, RTGCPHYS cb, bool fHasHCHandler, bool fRestoreAsRAM)
{
Log(("REMR3NotifyHandlerPhysicalDeregister: enmType=%d GCPhys=%RGp cb=%RGp fHasHCHandler=%RTbool fRestoreAsRAM=%RTbool RAM=%08x\n",
/** @todo this isn't right, MMIO can (in theory) be restored as RAM. */
if (enmType == PGMPHYSHANDLERTYPE_MMIO)
else if (fHasHCHandler)
{
if (!fRestoreAsRAM)
{
}
else
{
}
}
}
/**
* Notification about a successful PGMR3HandlerPhysicalModify() call.
*
* @param pVM VM Handle.
* @param enmType Handler type.
* @param GCPhysOld Old handler range address.
* @param GCPhysNew New handler range address.
* @param cb Size of the handler range.
* @param fHasHCHandler Set if the handler has a HC callback function.
* @param fRestoreAsRAM Whether the to restore it as normal RAM or as unassigned memory.
*/
REMR3DECL(void) REMR3NotifyHandlerPhysicalModify(PVM pVM, PGMPHYSHANDLERTYPE enmType, RTGCPHYS GCPhysOld, RTGCPHYS GCPhysNew, RTGCPHYS cb, bool fHasHCHandler, bool fRestoreAsRAM)
{
Log(("REMR3NotifyHandlerPhysicalModify: enmType=%d GCPhysOld=%RGp GCPhysNew=%RGp cb=%RGp fHasHCHandler=%RTbool fRestoreAsRAM=%RTbool\n",
if (fHasHCHandler)
{
/*
* Reset the old page.
*/
if (!fRestoreAsRAM)
else
{
/* This is not perfect, but it'll do for PD monitoring... */
}
/*
* Update the new page.
*/
}
}
/**
* Checks if we're handling access to this page or not.
*
* @returns true if we're trapping access.
* @returns false if we aren't.
* @param pVM The VM handle.
* @param GCPhys The physical address.
*
* @remark This function will only work correctly in VBOX_STRICT builds!
*/
{
#ifdef VBOX_STRICT
unsigned long off;
#else
return false;
#endif
}
/**
* Deals with a rare case in get_phys_addr_code where the code
* is being monitored.
*
* It could also be an MMIO page, in which case we will raise a fatal error.
*
* @returns The physical address corresponding to addr.
* @param env The cpu environment.
* @param addr The virtual address.
* @param pTLBEntry The TLB entry.
*/
{
{
/* If code memory is being monitored, appropriate IOTLB entry will have
handler IO type, and addend will provide real physical address, no
matter if we store VA in TLB or not, as handlers are always passed PA */
return ret;
}
LogRel(("\nTrying to execute code with memory type addr_code=%RGv addend=%RGp at %RGv! (iHandlerMemType=%#x iMMIOMemType=%#x IOTLB=%RGp)\n"
"*** handlers\n",
(RTGCPTR)pTLBEntry->addr_code, (RTGCPHYS)pTLBEntry->addend, (RTGCPTR)addr, pVM->rem.s.iHandlerMemType, pVM->rem.s.iMMIOMemType, (RTGCPHYS)ioTLBEntry));
LogRel(("*** mmio\n"));
LogRel(("*** phys\n"));
cpu_abort(env, "Trying to execute code with memory type addr_code=%RGv addend=%RGp at %RGv. (iHandlerMemType=%#x iMMIOMemType=%#x)\n",
(RTGCPTR)pTLBEntry->addr_code, (RTGCPHYS)pTLBEntry->addend, (RTGCPTR)addr, pVM->rem.s.iHandlerMemType, pVM->rem.s.iMMIOMemType);
}
/**
* Read guest RAM and ROM.
*
* @param SrcGCPhys The source address (guest physical).
* @param pvDst The destination address.
* @param cb Number of bytes
*/
{
#ifdef VBOX_DEBUG_PHYS
#endif
}
/**
* Read guest RAM and ROM, unsigned 8-bit.
*
* @param SrcGCPhys The source address (guest physical).
*/
{
#ifdef VBOX_DEBUG_PHYS
#endif
return val;
}
/**
* Read guest RAM and ROM, signed 8-bit.
*
* @param SrcGCPhys The source address (guest physical).
*/
{
#ifdef VBOX_DEBUG_PHYS
#endif
return val;
}
/**
* Read guest RAM and ROM, unsigned 16-bit.
*
* @param SrcGCPhys The source address (guest physical).
*/
{
#ifdef VBOX_DEBUG_PHYS
#endif
return val;
}
/**
* Read guest RAM and ROM, signed 16-bit.
*
* @param SrcGCPhys The source address (guest physical).
*/
{
#ifdef VBOX_DEBUG_PHYS
#endif
return val;
}
/**
* Read guest RAM and ROM, unsigned 32-bit.
*
* @param SrcGCPhys The source address (guest physical).
*/
{
#ifdef VBOX_DEBUG_PHYS
#endif
return val;
}
/**
* Read guest RAM and ROM, signed 32-bit.
*
* @param SrcGCPhys The source address (guest physical).
*/
{
#ifdef VBOX_DEBUG_PHYS
#endif
return val;
}
/**
* Read guest RAM and ROM, unsigned 64-bit.
*
* @param SrcGCPhys The source address (guest physical).
*/
{
#ifdef VBOX_DEBUG_PHYS
#endif
return val;
}
/**
* Read guest RAM and ROM, signed 64-bit.
*
* @param SrcGCPhys The source address (guest physical).
*/
{
#ifdef VBOX_DEBUG_PHYS
#endif
return val;
}
/**
* Write guest RAM.
*
* @param DstGCPhys The destination address (guest physical).
* @param pvSrc The source address.
* @param cb Number of bytes to write
*/
{
#ifdef VBOX_DEBUG_PHYS
#endif
}
/**
* Write guest RAM, unsigned 8-bit.
*
* @param DstGCPhys The destination address (guest physical).
* @param val Value
*/
{
#ifdef VBOX_DEBUG_PHYS
#endif
}
/**
* Write guest RAM, unsigned 8-bit.
*
* @param DstGCPhys The destination address (guest physical).
* @param val Value
*/
{
#ifdef VBOX_DEBUG_PHYS
#endif
}
/**
* Write guest RAM, unsigned 32-bit.
*
* @param DstGCPhys The destination address (guest physical).
* @param val Value
*/
{
#ifdef VBOX_DEBUG_PHYS
#endif
}
/**
* Write guest RAM, unsigned 64-bit.
*
* @param DstGCPhys The destination address (guest physical).
* @param val Value
*/
{
#ifdef VBOX_DEBUG_PHYS
#endif
}
#define LOG_GROUP LOG_GROUP_REM_MMIO
/** Read MMIO memory. */
{
return u32;
}
/** Read MMIO memory. */
{
return u32;
}
/** Read MMIO memory. */
{
return u32;
}
/** Write to MMIO memory. */
{
int rc;
}
/** Write to MMIO memory. */
{
int rc;
}
/** Write to MMIO memory. */
{
int rc;
}
#define LOG_GROUP LOG_GROUP_REM_HANDLER
/* !!!WARNING!!! This is extremely hackish right now, we assume it's only for LFB access! !!!WARNING!!! */
{
return u8;
}
{
return u16;
}
{
return u32;
}
{
}
{
}
{
}
/* -+- disassembly -+- */
#define LOG_GROUP LOG_GROUP_REM_DISAS
/**
* Enables or disables singled stepped disassembly.
*
* @returns VBox status code.
* @param pVM VM handle.
* @param fEnable To enable set this flag, to disable clear it.
*/
{
if (fEnable)
else
return VINF_SUCCESS;
}
/**
* Enables or disables singled stepped disassembly.
*
* @returns VBox status code.
* @param pVM VM handle.
* @param fEnable To enable set this flag, to disable clear it.
*/
{
int rc;
rc = VMR3ReqCall(pVM, VMREQDEST_ANY, &pReq, RT_INDEFINITE_WAIT, (PFNRT)remR3DisasEnableStepping, 2, pVM, fEnable);
if (RT_SUCCESS(rc))
return rc;
}
/**
* External Debugger Command: .remstep [on|off|1|0]
*/
static DECLCALLBACK(int) remR3CmdDisasEnableStepping(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
bool fEnable;
int rc;
/* print status */
if (cArgs == 0)
/* convert the argument and change the mode. */
if (RT_FAILURE(rc))
if (RT_FAILURE(rc))
return rc;
}
#endif
/**
* Disassembles n instructions and prints them to the log.
*
* @returns Success indicator.
* @param env Pointer to the recompiler CPU structure.
* @param f32BitCode Indicates that whether or not the code should
* be disassembled as 16 or 32 bit. If -1 the CS
* selector will be inspected.
* @param nrInstructions Nr of instructions to disassemble
* @param pszPrefix
* @remark not currently used for anything but ad-hoc debugging.
*/
{
int i, rc;
/*
* Determin 16/32 bit mode.
*/
if (f32BitCode == -1)
/*
* Convert cs:eip to host context address.
* We don't care to much about cross page correctness presently.
*/
{
/* convert eip to physical address. */
(void**)&pvPC);
if (RT_FAILURE(rc))
{
return false;
}
}
else
{
/* physical address */
(void**)&pvPC);
if (RT_FAILURE(rc))
return false;
}
/*
* Disassemble.
*/
//Cpu.dwUserData[0] = (uintptr_t)pVM;
//Cpu.dwUserData[1] = (uintptr_t)pvPC;
//Cpu.dwUserData[2] = GCPtrPC;
for (i=0;i<nrInstructions;i++)
{
char szOutput[256];
return false;
if (pszPrefix)
else
}
return true;
}
/** @todo need to test the new code, using the old code in the mean while. */
#define USE_OLD_DUMP_AND_DISASSEMBLY
/**
* Disassembles one instruction and prints it to the log.
*
* @returns Success indicator.
* @param env Pointer to the recompiler CPU structure.
* @param f32BitCode Indicates that whether or not the code should
* be disassembled as 16 or 32 bit. If -1 the CS
* selector will be inspected.
* @param pszPrefix
*/
{
#ifdef USE_OLD_DUMP_AND_DISASSEMBLY
char szOutput[256];
/* Doesn't work in long mode. */
return false;
/*
* Determin 16/32 bit mode.
*/
if (f32BitCode == -1)
/*
* Log registers
*/
if (LogIs2Enabled())
{
}
/*
* Convert cs:eip to host context address.
* We don't care to much about cross page correctness presently.
*/
{
/* convert eip to physical address. */
(void**)&pvPC);
if (RT_FAILURE(rc))
{
return false;
}
}
else
{
/* physical address */
if (RT_FAILURE(rc))
return false;
}
/*
* Disassemble.
*/
//Cpu.dwUserData[0] = (uintptr_t)pVM;
//Cpu.dwUserData[1] = (uintptr_t)pvPC;
//Cpu.dwUserData[2] = GCPtrPC;
return false;
if (!f32BitCode)
{
if (pszPrefix)
else
}
else
{
if (pszPrefix)
else
}
return true;
#else /* !USE_OLD_DUMP_AND_DISASSEMBLY */
const bool fLog = LogIsEnabled();
const bool fLog2 = LogIs2Enabled();
int rc = VINF_SUCCESS;
/*
* Don't bother if there ain't any log output to do.
*/
return true;
/*
* Update the state so DBGF reads the correct register values.
*/
/*
* Log registers if requested.
*/
if (!fLog2)
/*
* Disassemble to log.
*/
if (fLog)
return RT_SUCCESS(rc);
#endif
}
/**
* Disassemble recompiled code.
*
* @param phFileIgnored Ignored, logfile usually.
* @param pvCode Pointer to the code block.
* @param cb Size of the code block.
*/
{
#ifdef DEBUG_TMP_LOGGING
#else
# define DISAS_PRINTF(x...) RTLogPrintf(x)
if (LogIs2Enabled())
#endif
{
unsigned off = 0;
char szOutput[256];
#ifdef RT_ARCH_X86
#else
#endif
{
else
{
DISAS_PRINTF("disas error\n");
cbInstr = 1;
#ifdef RT_ARCH_AMD64 /** @todo remove when DISInstr starts supporing 64-bit code. */
break;
#endif
}
}
}
}
/**
* Disassemble guest code.
*
* @param phFileIgnored Ignored, logfile usually.
* @param uCode The guest address of the code to disassemble. (flat?)
* @param cb Number of bytes to disassemble.
* @param fFlags Flags, probably something which tells if this is 16, 32 or 64 bit code.
*/
{
#ifdef DEBUG_TMP_LOGGING
#else
# define DISAS_PRINTF(x...) RTLogPrintf(x)
if (LogIs2Enabled())
#endif
{
/*
* Update the state so DBGF reads the correct register values (flags).
*/
/*
* Do the disassembling.
*/
for (;;)
{
char szBuf[256];
cs,
eip,
0,
&cbInstr);
if (RT_SUCCESS(rc))
else
{
cbInstr = 1;
}
/* next */
break;
}
}
}
/**
* Looks up a guest symbol.
*
* @returns Pointer to symbol name. This is a static buffer.
* @param orig_addr The address in question.
*/
{
RTGCINTPTR off = 0;
if (RT_SUCCESS(rc))
{
if (!off)
else if (off > 0)
else
return szSym;
}
return "<N/A>";
}
#define LOG_GROUP LOG_GROUP_REM
/* -+- FF notifications -+- */
/**
* Notification about a pending interrupt.
*
* @param pVM VM Handle.
* @param u8Interrupt Interrupt
* @thread The emulation thread.
*/
{
}
/**
* Notification about a pending interrupt.
*
* @returns Pending interrupt or REM_NO_PENDING_IRQ
* @param pVM VM Handle.
* @thread The emulation thread.
*/
{
}
/**
* Notification about the interrupt FF being set.
*
* @param pVM VM Handle.
* @thread The emulation thread.
*/
{
(pVM->rem.s.Env.eflags & IF_MASK) && !(pVM->rem.s.Env.hflags & HF_INHIBIT_IRQ_MASK) ? "enabled" : "disabled"));
{
}
}
/**
* Notification about the interrupt FF being set.
*
* @param pVM VM Handle.
* @thread Any.
*/
{
LogFlow(("REMR3NotifyInterruptClear:\n"));
}
/**
* Notification about pending timer(s).
*
* @param pVM VM Handle.
* @thread Any.
*/
{
#ifndef DEBUG_bird
#endif
{
}
}
/**
* Notification about pending DMA transfers.
*
* @param pVM VM Handle.
* @thread Any.
*/
{
{
}
}
/**
* Notification about pending timer(s).
*
* @param pVM VM Handle.
* @thread Any.
*/
{
{
}
}
/**
* Notification about pending FF set by an external thread.
*
* @param pVM VM handle.
* @thread Any.
*/
{
{
}
}
#ifdef VBOX_WITH_STATISTICS
void remR3ProfileStart(int statcode)
{
switch(statcode)
{
break;
case STATS_QEMU_COMPILATION:
break;
break;
case STATS_QEMU_TOTAL:
break;
case STATS_QEMU_RUN_TIMERS:
pStat = &gStatTimers;
break;
case STATS_TLB_LOOKUP:
break;
case STATS_IRQ_HANDLING:
break;
case STATS_RAW_CHECK:
pStat = &gStatRawCheck;
break;
default:
return;
}
}
void remR3ProfileStop(int statcode)
{
switch(statcode)
{
break;
case STATS_QEMU_COMPILATION:
break;
break;
case STATS_QEMU_TOTAL:
break;
case STATS_QEMU_RUN_TIMERS:
pStat = &gStatTimers;
break;
case STATS_TLB_LOOKUP:
break;
case STATS_IRQ_HANDLING:
break;
case STATS_RAW_CHECK:
pStat = &gStatRawCheck;
break;
default:
return;
}
}
#endif
/**
* Raise an RC, force rem exit.
*
* @param pVM VM handle.
* @param rc The rc.
*/
{
}
/* -+- timers -+- */
{
}
/* -+- interrupts -+- */
{
}
{
int rc;
/* When we fail to forward interrupts directly in raw mode, we fall back to the recompiler.
* In that case we can't call PDMGetInterrupt anymore, because it has already cleared the interrupt
* with the (a)pic.
*/
/** @note We assume we will go directly to the recompiler to handle the pending interrupt! */
/** @todo r=bird: In the long run we should just do the interrupt handling in EM/CPUM/TRPM/somewhere and
* if we cannot execute the interrupt handler in raw-mode just reschedule to REM. Once that is done we
* remove this kludge. */
{
rc = VINF_SUCCESS;
}
else
if (RT_SUCCESS(rc))
{
return u8Interrupt;
}
return -1;
}
/* -+- local apic -+- */
{
}
{
if (RT_SUCCESS(rc))
{
return u64;
}
return 0;
}
{
}
{
if (RT_SUCCESS(rc))
{
return u8;
}
return 0;
}
{
if (RT_SUCCESS(rc))
{
return value;
}
/** @todo: exception ? */
return value;
}
{
/** @todo: exception if error ? */
}
{
}
{
}
/* -+- I/O Ports -+- */
#define LOG_GROUP LOG_GROUP_REM_IOPORT
{
int rc;
return;
{
return;
}
}
{
//Log2(("cpu_outw: addr=%#06x val=%#x\n", addr, val));
return;
{
return;
}
}
{
int rc;
return;
{
return;
}
}
{
{
return (int)u32;
}
{
return (int)u32;
}
return 0xff;
}
{
{
return (int)u32;
}
{
return (int)u32;
}
return 0xffff;
}
{
{
//if (addr==0x01f0 && u32 == 0x6b6d)
// loglevel = ~0;
return (int)u32;
}
{
return (int)u32;
}
return 0xffffffff;
}
#define LOG_GROUP LOG_GROUP_REM
/* -+- helpers and misc other interfaces -+- */
/**
* Perform the CPUID instruction.
*
* ASMCpuId cannot be invoked from some source files where this is used because of global
* register allocations.
*
* @param env Pointer to the recompiler CPU structure.
* @param uOperator CPUID operation (eax).
* @param pvEAX Where to store eax.
* @param pvEBX Where to store ebx.
* @param pvECX Where to store ecx.
* @param pvEDX Where to store edx.
*/
void remR3CpuId(CPUState *env, unsigned uOperator, void *pvEAX, void *pvEBX, void *pvECX, void *pvEDX)
{
CPUMGetGuestCpuId(env->pVM, uOperator, (uint32_t *)pvEAX, (uint32_t *)pvEBX, (uint32_t *)pvECX, (uint32_t *)pvEDX);
}
#if 0 /* not used */
/**
* Interface for qemu hardware to report back fatal errors.
*/
{
/*
* Bitch about it.
*/
/** @todo Add support for nested arg lists in the LogPrintfV routine! I've code for
* this in my Odin32 tree at home! */
RTLogPrintf("fatal error in virtual hardware:");
/*
* If we're in REM context we'll sync back the state before 'jumping' to
* the EMs failure handling.
*/
AssertMsgFailed(("EMR3FatalError returned!\n"));
}
#endif
/**
* Interface for the qemu cpu to report unhandled situation
* raising a fatal VM error.
*/
{
/*
* Bitch about it.
*/
#ifndef _MSC_VER
/** @todo: MSVC is right - it's not valid C */
#endif
/*
* If we're in REM context we'll sync back the state before 'jumping' to
* the EMs failure handling.
*/
AssertMsgFailed(("EMR3FatalError returned!\n"));
}
/**
* Aborts the VM.
*
* @param rc VBox error code.
*/
{
/*
* Bitch about it.
*/
/*
* Jump back to where we entered the recompiler.
*/
AssertMsgFailed(("EMR3FatalError returned!\n"));
}
/**
* Dumps a linux system call.
* @param pVM VM handle.
*/
{
static const char *apsz[] =
{
"sys_restart_syscall", /* 0 - old "setup()" system call, used for restarting */
"sys_exit",
"sys_fork",
"sys_read",
"sys_write",
"sys_open", /* 5 */
"sys_close",
"sys_waitpid",
"sys_creat",
"sys_link",
"sys_unlink", /* 10 */
"sys_execve",
"sys_chdir",
"sys_time",
"sys_mknod",
"sys_chmod", /* 15 */
"sys_lchown16",
"sys_ni_syscall", /* old break syscall holder */
"sys_stat",
"sys_lseek",
"sys_getpid", /* 20 */
"sys_mount",
"sys_oldumount",
"sys_setuid16",
"sys_getuid16",
"sys_stime", /* 25 */
"sys_ptrace",
"sys_alarm",
"sys_fstat",
"sys_pause",
"sys_utime", /* 30 */
"sys_ni_syscall", /* old stty syscall holder */
"sys_ni_syscall", /* old gtty syscall holder */
"sys_access",
"sys_nice",
"sys_ni_syscall", /* 35 - old ftime syscall holder */
"sys_sync",
"sys_kill",
"sys_rename",
"sys_mkdir",
"sys_rmdir", /* 40 */
"sys_dup",
"sys_pipe",
"sys_times",
"sys_ni_syscall", /* old prof syscall holder */
"sys_brk", /* 45 */
"sys_setgid16",
"sys_getgid16",
"sys_signal",
"sys_geteuid16",
"sys_getegid16", /* 50 */
"sys_acct",
"sys_umount", /* recycled never used phys() */
"sys_ni_syscall", /* old lock syscall holder */
"sys_ioctl",
"sys_fcntl", /* 55 */
"sys_ni_syscall", /* old mpx syscall holder */
"sys_setpgid",
"sys_ni_syscall", /* old ulimit syscall holder */
"sys_olduname",
"sys_umask", /* 60 */
"sys_chroot",
"sys_ustat",
"sys_dup2",
"sys_getppid",
"sys_getpgrp", /* 65 */
"sys_setsid",
"sys_sigaction",
"sys_sgetmask",
"sys_ssetmask",
"sys_setreuid16", /* 70 */
"sys_setregid16",
"sys_sigsuspend",
"sys_sigpending",
"sys_sethostname",
"sys_setrlimit", /* 75 */
"sys_old_getrlimit",
"sys_getrusage",
"sys_gettimeofday",
"sys_settimeofday",
"sys_getgroups16", /* 80 */
"sys_setgroups16",
"old_select",
"sys_symlink",
"sys_lstat",
"sys_readlink", /* 85 */
"sys_uselib",
"sys_swapon",
"sys_reboot",
"old_readdir",
"old_mmap", /* 90 */
"sys_munmap",
"sys_truncate",
"sys_ftruncate",
"sys_fchmod",
"sys_fchown16", /* 95 */
"sys_getpriority",
"sys_setpriority",
"sys_ni_syscall", /* old profil syscall holder */
"sys_statfs",
"sys_fstatfs", /* 100 */
"sys_ioperm",
"sys_socketcall",
"sys_syslog",
"sys_setitimer",
"sys_getitimer", /* 105 */
"sys_newstat",
"sys_newlstat",
"sys_newfstat",
"sys_uname",
"sys_iopl", /* 110 */
"sys_vhangup",
"sys_ni_syscall", /* old "idle" system call */
"sys_vm86old",
"sys_wait4",
"sys_swapoff", /* 115 */
"sys_sysinfo",
"sys_ipc",
"sys_fsync",
"sys_sigreturn",
"sys_clone", /* 120 */
"sys_setdomainname",
"sys_newuname",
"sys_modify_ldt",
"sys_adjtimex",
"sys_mprotect", /* 125 */
"sys_sigprocmask",
"sys_ni_syscall", /* old "create_module" */
"sys_init_module",
"sys_delete_module",
"sys_ni_syscall", /* 130: old "get_kernel_syms" */
"sys_quotactl",
"sys_getpgid",
"sys_fchdir",
"sys_bdflush",
"sys_sysfs", /* 135 */
"sys_personality",
"sys_ni_syscall", /* reserved for afs_syscall */
"sys_setfsuid16",
"sys_setfsgid16",
"sys_llseek", /* 140 */
"sys_getdents",
"sys_select",
"sys_flock",
"sys_msync",
"sys_readv", /* 145 */
"sys_writev",
"sys_getsid",
"sys_fdatasync",
"sys_sysctl",
"sys_mlock", /* 150 */
"sys_munlock",
"sys_mlockall",
"sys_munlockall",
"sys_sched_setparam",
"sys_sched_getparam", /* 155 */
"sys_sched_setscheduler",
"sys_sched_getscheduler",
"sys_sched_yield",
"sys_sched_get_priority_max",
"sys_sched_get_priority_min", /* 160 */
"sys_sched_rr_get_interval",
"sys_nanosleep",
"sys_mremap",
"sys_setresuid16",
"sys_getresuid16", /* 165 */
"sys_vm86",
"sys_ni_syscall", /* Old sys_query_module */
"sys_poll",
"sys_nfsservctl",
"sys_setresgid16", /* 170 */
"sys_getresgid16",
"sys_prctl",
"sys_rt_sigreturn",
"sys_rt_sigaction",
"sys_rt_sigprocmask", /* 175 */
"sys_rt_sigpending",
"sys_rt_sigtimedwait",
"sys_rt_sigqueueinfo",
"sys_rt_sigsuspend",
"sys_pread64", /* 180 */
"sys_pwrite64",
"sys_chown16",
"sys_getcwd",
"sys_capget",
"sys_capset", /* 185 */
"sys_sigaltstack",
"sys_sendfile",
"sys_ni_syscall", /* reserved for streams1 */
"sys_ni_syscall", /* reserved for streams2 */
"sys_vfork", /* 190 */
"sys_getrlimit",
"sys_mmap2",
"sys_truncate64",
"sys_ftruncate64",
"sys_stat64", /* 195 */
"sys_lstat64",
"sys_fstat64",
"sys_lchown",
"sys_getuid",
"sys_getgid", /* 200 */
"sys_geteuid",
"sys_getegid",
"sys_setreuid",
"sys_setregid",
"sys_getgroups", /* 205 */
"sys_setgroups",
"sys_fchown",
"sys_setresuid",
"sys_getresuid",
"sys_setresgid", /* 210 */
"sys_getresgid",
"sys_chown",
"sys_setuid",
"sys_setgid",
"sys_setfsuid", /* 215 */
"sys_setfsgid",
"sys_pivot_root",
"sys_mincore",
"sys_madvise",
"sys_getdents64", /* 220 */
"sys_fcntl64",
"sys_ni_syscall", /* reserved for TUX */
"sys_ni_syscall",
"sys_gettid",
"sys_readahead", /* 225 */
"sys_setxattr",
"sys_lsetxattr",
"sys_fsetxattr",
"sys_getxattr",
"sys_lgetxattr", /* 230 */
"sys_fgetxattr",
"sys_listxattr",
"sys_llistxattr",
"sys_flistxattr",
"sys_removexattr", /* 235 */
"sys_lremovexattr",
"sys_fremovexattr",
"sys_tkill",
"sys_sendfile64",
"sys_futex", /* 240 */
"sys_sched_setaffinity",
"sys_sched_getaffinity",
"sys_set_thread_area",
"sys_get_thread_area",
"sys_io_setup", /* 245 */
"sys_io_destroy",
"sys_io_getevents",
"sys_io_submit",
"sys_io_cancel",
"sys_fadvise64", /* 250 */
"sys_ni_syscall",
"sys_exit_group",
"sys_lookup_dcookie",
"sys_epoll_create",
"sys_epoll_ctl", /* 255 */
"sys_epoll_wait",
"sys_remap_file_pages",
"sys_set_tid_address",
"sys_timer_create",
"sys_timer_settime", /* 260 */
"sys_timer_gettime",
"sys_timer_getoverrun",
"sys_timer_delete",
"sys_clock_settime",
"sys_clock_gettime", /* 265 */
"sys_clock_getres",
"sys_clock_nanosleep",
"sys_statfs64",
"sys_fstatfs64",
"sys_tgkill", /* 270 */
"sys_utimes",
"sys_fadvise64_64",
"sys_ni_syscall" /* sys_vserver */
};
switch (uEAX)
{
default:
Log(("REM: linux syscall %3d: %s (eip=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x ebp=%08x)\n",
else
break;
}
}
/**
* Dumps an OpenBSD system call.
* @param pVM VM handle.
*/
{
static const char *apsz[] =
{
"SYS_syscall", //0
"SYS_exit", //1
"SYS_fork", //2
"SYS_read", //3
"SYS_write", //4
"SYS_open", //5
"SYS_close", //6
"SYS_wait4", //7
"SYS_8",
"SYS_link", //9
"SYS_unlink", //10
"SYS_11",
"SYS_chdir", //12
"SYS_fchdir", //13
"SYS_mknod", //14
"SYS_chmod", //15
"SYS_chown", //16
"SYS_break", //17
"SYS_18",
"SYS_19",
"SYS_getpid", //20
"SYS_mount", //21
"SYS_unmount", //22
"SYS_setuid", //23
"SYS_getuid", //24
"SYS_geteuid", //25
"SYS_ptrace", //26
"SYS_recvmsg", //27
"SYS_sendmsg", //28
"SYS_recvfrom", //29
"SYS_accept", //30
"SYS_getpeername", //31
"SYS_getsockname", //32
"SYS_access", //33
"SYS_chflags", //34
"SYS_fchflags", //35
"SYS_sync", //36
"SYS_kill", //37
"SYS_38",
"SYS_getppid", //39
"SYS_40",
"SYS_dup", //41
"SYS_opipe", //42
"SYS_getegid", //43
"SYS_profil", //44
"SYS_ktrace", //45
"SYS_sigaction", //46
"SYS_getgid", //47
"SYS_sigprocmask", //48
"SYS_getlogin", //49
"SYS_setlogin", //50
"SYS_acct", //51
"SYS_sigpending", //52
"SYS_osigaltstack", //53
"SYS_ioctl", //54
"SYS_reboot", //55
"SYS_revoke", //56
"SYS_symlink", //57
"SYS_readlink", //58
"SYS_execve", //59
"SYS_umask", //60
"SYS_chroot", //61
"SYS_62",
"SYS_63",
"SYS_64",
"SYS_65",
"SYS_vfork", //66
"SYS_67",
"SYS_68",
"SYS_sbrk", //69
"SYS_sstk", //70
"SYS_61",
"SYS_vadvise", //72
"SYS_munmap", //73
"SYS_mprotect", //74
"SYS_madvise", //75
"SYS_76",
"SYS_77",
"SYS_mincore", //78
"SYS_getgroups", //79
"SYS_setgroups", //80
"SYS_getpgrp", //81
"SYS_setpgid", //82
"SYS_setitimer", //83
"SYS_84",
"SYS_85",
"SYS_getitimer", //86
"SYS_87",
"SYS_88",
"SYS_89",
"SYS_dup2", //90
"SYS_91",
"SYS_fcntl", //92
"SYS_select", //93
"SYS_94",
"SYS_fsync", //95
"SYS_setpriority", //96
"SYS_socket", //97
"SYS_connect", //98
"SYS_99",
"SYS_getpriority", //100
"SYS_101",
"SYS_102",
"SYS_sigreturn", //103
"SYS_bind", //104
"SYS_setsockopt", //105
"SYS_listen", //106
"SYS_107",
"SYS_108",
"SYS_109",
"SYS_110",
"SYS_sigsuspend", //111
"SYS_112",
"SYS_113",
"SYS_114",
"SYS_115",
"SYS_gettimeofday", //116
"SYS_getrusage", //117
"SYS_getsockopt", //118
"SYS_119",
"SYS_readv", //120
"SYS_writev", //121
"SYS_settimeofday", //122
"SYS_fchown", //123
"SYS_fchmod", //124
"SYS_125",
"SYS_setreuid", //126
"SYS_setregid", //127
"SYS_rename", //128
"SYS_129",
"SYS_130",
"SYS_flock", //131
"SYS_mkfifo", //132
"SYS_sendto", //133
"SYS_shutdown", //134
"SYS_socketpair", //135
"SYS_mkdir", //136
"SYS_rmdir", //137
"SYS_utimes", //138
"SYS_139",
"SYS_adjtime", //140
"SYS_141",
"SYS_142",
"SYS_143",
"SYS_144",
"SYS_145",
"SYS_146",
"SYS_setsid", //147
"SYS_quotactl", //148
"SYS_149",
"SYS_150",
"SYS_151",
"SYS_152",
"SYS_153",
"SYS_154",
"SYS_nfssvc", //155
"SYS_156",
"SYS_157",
"SYS_158",
"SYS_159",
"SYS_160",
"SYS_getfh", //161
"SYS_162",
"SYS_163",
"SYS_164",
"SYS_sysarch", //165
"SYS_166",
"SYS_167",
"SYS_168",
"SYS_169",
"SYS_170",
"SYS_171",
"SYS_172",
"SYS_pread", //173
"SYS_pwrite", //174
"SYS_175",
"SYS_176",
"SYS_177",
"SYS_178",
"SYS_179",
"SYS_180",
"SYS_setgid", //181
"SYS_setegid", //182
"SYS_seteuid", //183
"SYS_lfs_bmapv", //184
"SYS_lfs_markv", //185
"SYS_lfs_segclean", //186
"SYS_lfs_segwait", //187
"SYS_188",
"SYS_189",
"SYS_190",
"SYS_pathconf", //191
"SYS_fpathconf", //192
"SYS_swapctl", //193
"SYS_getrlimit", //194
"SYS_setrlimit", //195
"SYS_getdirentries", //196
"SYS_mmap", //197
"SYS___syscall", //198
"SYS_lseek", //199
"SYS_truncate", //200
"SYS_ftruncate", //201
"SYS___sysctl", //202
"SYS_mlock", //203
"SYS_munlock", //204
"SYS_205",
"SYS_futimes", //206
"SYS_getpgid", //207
"SYS_xfspioctl", //208
"SYS_209",
"SYS_210",
"SYS_211",
"SYS_212",
"SYS_213",
"SYS_214",
"SYS_215",
"SYS_216",
"SYS_217",
"SYS_218",
"SYS_219",
"SYS_220",
"SYS_semget", //221
"SYS_222",
"SYS_223",
"SYS_224",
"SYS_msgget", //225
"SYS_msgsnd", //226
"SYS_msgrcv", //227
"SYS_shmat", //228
"SYS_229",
"SYS_shmdt", //230
"SYS_231",
"SYS_clock_gettime", //232
"SYS_clock_settime", //233
"SYS_clock_getres", //234
"SYS_235",
"SYS_236",
"SYS_237",
"SYS_238",
"SYS_239",
"SYS_nanosleep", //240
"SYS_241",
"SYS_242",
"SYS_243",
"SYS_244",
"SYS_245",
"SYS_246",
"SYS_247",
"SYS_248",
"SYS_249",
"SYS_minherit", //250
"SYS_rfork", //251
"SYS_poll", //252
"SYS_issetugid", //253
"SYS_lchown", //254
"SYS_getsid", //255
"SYS_msync", //256
"SYS_257",
"SYS_258",
"SYS_259",
"SYS_getfsstat", //260
"SYS_statfs", //261
"SYS_fstatfs", //262
"SYS_pipe", //263
"SYS_fhopen", //264
"SYS_265",
"SYS_fhstatfs", //266
"SYS_preadv", //267
"SYS_pwritev", //268
"SYS_kqueue", //269
"SYS_kevent", //270
"SYS_mlockall", //271
"SYS_munlockall", //272
"SYS_getpeereid", //273
"SYS_274",
"SYS_275",
"SYS_276",
"SYS_277",
"SYS_278",
"SYS_279",
"SYS_280",
"SYS_getresuid", //281
"SYS_setresuid", //282
"SYS_getresgid", //283
"SYS_setresgid", //284
"SYS_285",
"SYS_mquery", //286
"SYS_closefrom", //287
"SYS_sigaltstack", //288
"SYS_shmget", //289
"SYS_semop", //290
"SYS_stat", //291
"SYS_fstat", //292
"SYS_lstat", //293
"SYS_fhstat", //294
"SYS___semctl", //295
"SYS_shmctl", //296
"SYS_msgctl", //297
"SYS_MAXSYSCALL", //298
//299
//300
};
if (!LogIsEnabled())
return;
switch (uEAX)
{
default:
{
RTLogPrintf("REM: OpenBSD syscall %3d: %s (eip=%08x %08x %08x %08x %08x %08x %08x %08x %08x)\n",
}
else
break;
}
}
/**
* The Dll main entry point (stub).
*/
{
return true;
}
{
while (size-- > 0)
return dst;
}
#endif
{
}