2013-08-21 11:37:21 +02:00
|
|
|
/*
|
|
|
|
* \brief VirtualBox SUPLib supplements
|
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2013-08-20
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (C) 2013 Genode Labs GmbH
|
|
|
|
*
|
|
|
|
* This file is distributed under the terms of the GNU General Public License
|
|
|
|
* version 2.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Genode includes */
|
|
|
|
#include <os/attached_ram_dataspace.h>
|
|
|
|
#include <base/semaphore.h>
|
2014-05-23 09:26:57 +02:00
|
|
|
#include <os/timed_semaphore.h>
|
2015-02-09 17:06:28 +01:00
|
|
|
#include <trace/timestamp.h>
|
2013-08-21 11:37:21 +02:00
|
|
|
|
|
|
|
/* Genode/Virtualbox includes */
|
|
|
|
#include "sup.h"
|
|
|
|
|
|
|
|
/* VirtualBox includes */
|
2014-09-23 13:01:47 +02:00
|
|
|
#include <iprt/semaphore.h>
|
|
|
|
#include <iprt/ldr.h>
|
2015-02-09 17:06:28 +01:00
|
|
|
#include <iprt/uint128.h>
|
2013-08-21 11:37:21 +02:00
|
|
|
#include <VBox/err.h>
|
|
|
|
|
2015-07-24 18:38:34 +02:00
|
|
|
/* libc memory allocator */
|
|
|
|
#include <libc_mem_alloc.h>
|
|
|
|
|
2013-08-21 11:37:21 +02:00
|
|
|
|
|
|
|
struct Attached_gip : Genode::Attached_ram_dataspace
|
|
|
|
{
|
|
|
|
Attached_gip()
|
|
|
|
: Attached_ram_dataspace(Genode::env()->ram_session(), PAGE_SIZE)
|
|
|
|
{ }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
enum {
|
2015-09-25 14:54:34 +02:00
|
|
|
UPDATE_HZ = 1000,
|
2013-08-21 11:37:21 +02:00
|
|
|
UPDATE_MS = 1000 / UPDATE_HZ,
|
|
|
|
UPDATE_NS = UPDATE_MS * 1000 * 1000,
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
PSUPGLOBALINFOPAGE g_pSUPGlobalInfoPage;
|
|
|
|
|
|
|
|
|
2015-09-25 14:54:34 +02:00
|
|
|
struct Periodic_gip : public Genode::Thread<4096>
|
|
|
|
{
|
|
|
|
Periodic_gip() : Thread("periodic_gip") { start(); }
|
2013-08-21 11:37:21 +02:00
|
|
|
|
2015-09-25 14:54:34 +02:00
|
|
|
static void update()
|
2014-05-23 09:26:57 +02:00
|
|
|
{
|
|
|
|
/**
|
|
|
|
* We're using rdtsc here since timer_session->elapsed_ms produces
|
|
|
|
* instable results when the timer service is using the Genode PIC
|
|
|
|
* driver as done for base-nova currently.
|
|
|
|
*/
|
2013-08-21 11:37:21 +02:00
|
|
|
|
2015-05-29 19:39:14 +02:00
|
|
|
Genode::uint64_t tsc_current = Genode::Trace::timestamp();
|
2013-08-21 11:37:21 +02:00
|
|
|
|
2015-02-09 17:06:28 +01:00
|
|
|
/*
|
|
|
|
* Convert tsc to nanoseconds.
|
|
|
|
*
|
|
|
|
* There is no 'uint128_t' type on x86_32, so we use the 128-bit type
|
|
|
|
* and functions provided by VirtualBox.
|
|
|
|
*
|
|
|
|
* nanots128 = tsc_current * 1000*1000*1000 / genode_cpu_hz()
|
|
|
|
*
|
|
|
|
*/
|
2013-08-21 11:37:21 +02:00
|
|
|
|
2015-02-09 17:06:28 +01:00
|
|
|
RTUINT128U nanots128;
|
|
|
|
RTUInt128AssignU64(&nanots128, tsc_current);
|
2013-08-21 11:37:21 +02:00
|
|
|
|
2015-02-09 17:06:28 +01:00
|
|
|
RTUINT128U multiplier;
|
|
|
|
RTUInt128AssignU32(&multiplier, 1000*1000*1000);
|
|
|
|
RTUInt128AssignMul(&nanots128, &multiplier);
|
2013-08-21 11:37:21 +02:00
|
|
|
|
2015-02-09 17:06:28 +01:00
|
|
|
RTUINT128U divisor;
|
|
|
|
RTUInt128AssignU64(&divisor, genode_cpu_hz());
|
|
|
|
RTUInt128AssignDiv(&nanots128, &divisor);
|
2013-08-21 11:37:21 +02:00
|
|
|
|
2014-05-23 09:26:57 +02:00
|
|
|
SUPGIPCPU *cpu = &g_pSUPGlobalInfoPage->aCPUs[0];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Transaction id must be incremented before and after update,
|
|
|
|
* read struct SUPGIPCPU description for more details.
|
|
|
|
*/
|
|
|
|
ASMAtomicIncU32(&cpu->u32TransactionId);
|
|
|
|
|
2015-02-09 17:06:28 +01:00
|
|
|
cpu->u64TSC = tsc_current;
|
|
|
|
cpu->u64NanoTS = nanots128.s.Lo;
|
2014-05-23 09:26:57 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Transaction id must be incremented before and after update,
|
|
|
|
* read struct SUPGIPCPU description for more details.
|
|
|
|
*/
|
|
|
|
ASMAtomicIncU32(&cpu->u32TransactionId);
|
|
|
|
}
|
2013-08-21 11:37:21 +02:00
|
|
|
|
2015-09-25 14:54:34 +02:00
|
|
|
void entry() override { genode_update_tsc(update, UPDATE_MS * 1000); }
|
|
|
|
};
|
2013-08-21 11:37:21 +02:00
|
|
|
|
|
|
|
|
|
|
|
int SUPR3Init(PSUPDRVSESSION *ppSession)
|
|
|
|
{
|
2014-05-23 09:26:57 +02:00
|
|
|
static bool initialized = false;
|
2013-08-21 11:37:21 +02:00
|
|
|
|
|
|
|
if (initialized) return VINF_SUCCESS;
|
|
|
|
|
|
|
|
static Attached_gip gip;
|
|
|
|
|
|
|
|
g_pSUPGlobalInfoPage = gip.local_addr<SUPGLOBALINFOPAGE>();
|
|
|
|
|
|
|
|
/* checked by TMR3Init */
|
|
|
|
g_pSUPGlobalInfoPage->u32Version = SUPGLOBALINFOPAGE_VERSION;
|
|
|
|
g_pSUPGlobalInfoPage->u32Magic = SUPGLOBALINFOPAGE_MAGIC;
|
|
|
|
g_pSUPGlobalInfoPage->u32Mode = SUPGIPMODE_SYNC_TSC;
|
|
|
|
g_pSUPGlobalInfoPage->cCpus = 1;
|
|
|
|
g_pSUPGlobalInfoPage->cPages = 1;
|
|
|
|
g_pSUPGlobalInfoPage->u32UpdateHz = UPDATE_HZ;
|
|
|
|
g_pSUPGlobalInfoPage->u32UpdateIntervalNS = UPDATE_NS;
|
|
|
|
// g_pSUPGlobalInfoPage->u64NanoTSLastUpdateHz =
|
|
|
|
// g_pSUPGlobalInfoPage->OnlineCpuSet =
|
|
|
|
// g_pSUPGlobalInfoPage->PresentCpuSet =
|
|
|
|
// g_pSUPGlobalInfoPage->PossibleCpuSet =
|
|
|
|
g_pSUPGlobalInfoPage->cOnlineCpus = 0;
|
|
|
|
g_pSUPGlobalInfoPage->cPresentCpus = 0;
|
|
|
|
g_pSUPGlobalInfoPage->cPossibleCpus = 0;
|
|
|
|
g_pSUPGlobalInfoPage->idCpuMax = 0;
|
|
|
|
|
|
|
|
SUPGIPCPU *cpu = &g_pSUPGlobalInfoPage->aCPUs[0];
|
|
|
|
|
|
|
|
cpu->u32TransactionId = 0;
|
|
|
|
cpu->u32UpdateIntervalTSC = genode_cpu_hz() / UPDATE_HZ;
|
|
|
|
cpu->u64NanoTS = 0ULL;
|
|
|
|
cpu->u64TSC = 0ULL;
|
|
|
|
cpu->u64CpuHz = genode_cpu_hz();
|
|
|
|
cpu->cErrors = 0;
|
|
|
|
cpu->iTSCHistoryHead = 0;
|
|
|
|
// cpu->au32TSCHistory[8] =
|
|
|
|
cpu->u32PrevUpdateIntervalNS = UPDATE_NS;
|
|
|
|
cpu->enmState = SUPGIPCPUSTATE_ONLINE;
|
|
|
|
cpu->idCpu = 0;
|
|
|
|
cpu->iCpuSet = 0;
|
|
|
|
cpu->idApic = 0;
|
|
|
|
|
2014-05-23 09:26:57 +02:00
|
|
|
/* schedule periodic call of GIP update function */
|
2015-09-25 14:54:34 +02:00
|
|
|
static Periodic_gip periodic_gip;
|
2013-08-21 11:37:21 +02:00
|
|
|
|
|
|
|
initialized = true;
|
|
|
|
|
|
|
|
return VINF_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-23 13:01:47 +02:00
|
|
|
int SUPR3Term(bool) { return VINF_SUCCESS; }
|
|
|
|
|
|
|
|
|
2013-08-21 11:37:21 +02:00
|
|
|
int SUPR3GipGetPhys(PRTHCPHYS pHCPhys)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Return VMM-local address as physical address. This address is
|
|
|
|
* then fed to MMR3HyperMapHCPhys. (TMR3Init)
|
|
|
|
*/
|
|
|
|
*pHCPhys = (RTHCPHYS)g_pSUPGlobalInfoPage;
|
|
|
|
|
|
|
|
return VINF_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-23 13:01:47 +02:00
|
|
|
int SUPR3HardenedLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod,
|
|
|
|
uint32_t fFlags, PRTERRINFO pErrInfo)
|
|
|
|
{
|
|
|
|
return RTLdrLoad(pszFilename, phLdrMod);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint32_t SUPSemEventMultiGetResolution(PSUPDRVSESSION)
|
|
|
|
{
|
|
|
|
return 100000*10; /* called by 'vmR3HaltGlobal1Init' */
|
|
|
|
}
|
|
|
|
|
2013-08-21 11:37:21 +02:00
|
|
|
int SUPSemEventCreate(PSUPDRVSESSION pSession, PSUPSEMEVENT phEvent)
|
|
|
|
{
|
|
|
|
*phEvent = (SUPSEMEVENT)new Genode::Semaphore();
|
|
|
|
return VINF_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SUPSemEventClose(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent)
|
|
|
|
{
|
|
|
|
if (hEvent)
|
|
|
|
delete reinterpret_cast<Genode::Semaphore *>(hEvent);
|
|
|
|
return VINF_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SUPSemEventSignal(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent)
|
|
|
|
{
|
|
|
|
if (hEvent)
|
|
|
|
reinterpret_cast<Genode::Semaphore *>(hEvent)->up();
|
|
|
|
else
|
2014-09-23 13:01:47 +02:00
|
|
|
PERR("%s called - not implemented", __FUNCTION__);
|
2013-08-21 11:37:21 +02:00
|
|
|
|
|
|
|
return VINF_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int SUPSemEventWaitNoResume(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent,
|
|
|
|
uint32_t cMillies)
|
|
|
|
{
|
|
|
|
if (hEvent && cMillies == RT_INDEFINITE_WAIT)
|
|
|
|
reinterpret_cast<Genode::Semaphore *>(hEvent)->down();
|
|
|
|
else {
|
2014-09-23 13:01:47 +02:00
|
|
|
PERR("%s called millis=%u - not implemented", __FUNCTION__, cMillies);
|
2013-08-21 11:37:21 +02:00
|
|
|
reinterpret_cast<Genode::Semaphore *>(hEvent)->down();
|
|
|
|
}
|
|
|
|
|
|
|
|
return VINF_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-23 13:01:47 +02:00
|
|
|
SUPDECL(int) SUPSemEventMultiCreate(PSUPDRVSESSION,
|
|
|
|
PSUPSEMEVENTMULTI phEventMulti)
|
|
|
|
{
|
|
|
|
RTSEMEVENTMULTI sem;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Input validation.
|
|
|
|
*/
|
|
|
|
AssertPtrReturn(phEventMulti, VERR_INVALID_POINTER);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create the event semaphore object.
|
|
|
|
*/
|
|
|
|
int rc = RTSemEventMultiCreate(&sem);
|
|
|
|
|
|
|
|
static_assert(sizeof(sem) == sizeof(*phEventMulti), "oi");
|
|
|
|
*phEventMulti = reinterpret_cast<SUPSEMEVENTMULTI>(sem);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SUPDECL(int) SUPSemEventMultiClose(PSUPDRVSESSION, SUPSEMEVENTMULTI hEvMulti)
|
|
|
|
{
|
|
|
|
return RTSemEventMultiDestroy(reinterpret_cast<RTSEMEVENTMULTI>(hEvMulti));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-21 11:37:21 +02:00
|
|
|
int SUPR3CallVMMR0(PVMR0 pVMR0, VMCPUID idCpu, unsigned uOperation,
|
|
|
|
void *pvArg)
|
|
|
|
{
|
|
|
|
if (uOperation == VMMR0_DO_CALL_HYPERVISOR) {
|
|
|
|
PDBG("VMMR0_DO_CALL_HYPERVISOR - doing nothing");
|
|
|
|
return VINF_SUCCESS;
|
|
|
|
}
|
2014-09-23 13:01:47 +02:00
|
|
|
if (uOperation == VMMR0_DO_VMMR0_TERM) {
|
|
|
|
PDBG("VMMR0_DO_VMMR0_TERM - doing nothing");
|
|
|
|
return VINF_SUCCESS;
|
|
|
|
}
|
|
|
|
if (uOperation == VMMR0_DO_GVMM_DESTROY_VM) {
|
|
|
|
PDBG("VMMR0_DO_GVMM_DESTROY_VM - doing nothing");
|
|
|
|
return VINF_SUCCESS;
|
|
|
|
}
|
2013-08-21 11:37:21 +02:00
|
|
|
|
2014-09-23 13:01:47 +02:00
|
|
|
AssertMsg(uOperation != VMMR0_DO_VMMR0_TERM &&
|
|
|
|
uOperation != VMMR0_DO_CALL_HYPERVISOR &&
|
|
|
|
uOperation != VMMR0_DO_GVMM_DESTROY_VM,
|
|
|
|
("SUPR3CallVMMR0Ex: unhandled uOperation %d", uOperation));
|
|
|
|
return VERR_GENERAL_FAILURE;
|
2013-08-21 11:37:21 +02:00
|
|
|
}
|
2015-07-24 18:38:34 +02:00
|
|
|
|
|
|
|
|
|
|
|
void genode_VMMR0_DO_GVMM_CREATE_VM(PSUPVMMR0REQHDR pReqHdr)
|
|
|
|
{
|
|
|
|
GVMMCREATEVMREQ &req = reinterpret_cast<GVMMCREATEVMREQ &>(*pReqHdr);
|
|
|
|
|
|
|
|
size_t const cCpus = req.cCpus;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate and initialize VM struct
|
|
|
|
*
|
|
|
|
* The VM struct is followed by the variable-sizedA array of VMCPU
|
|
|
|
* objects. 'RT_UOFFSETOF' is used to determine the size including
|
|
|
|
* the VMCPU array.
|
|
|
|
*
|
|
|
|
* VM struct must be page-aligned, which is checked at least in
|
|
|
|
* PDMR3CritSectGetNop().
|
|
|
|
*/
|
|
|
|
size_t const cbVM = RT_UOFFSETOF(VM, aCpus[cCpus]);
|
|
|
|
VM *pVM = (VM *)Libc::mem_alloc()->alloc(cbVM, Genode::log2(PAGE_SIZE));
|
|
|
|
Genode::memset(pVM, 0, cbVM);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* On Genode, VMMR0 and VMMR3 share a single address space. Hence, the
|
|
|
|
* same pVM pointer is valid as pVMR0 and pVMR3.
|
|
|
|
*/
|
|
|
|
pVM->enmVMState = VMSTATE_CREATING;
|
|
|
|
pVM->pVMR0 = (RTHCUINTPTR)pVM;
|
|
|
|
pVM->pVMRC = (RTGCUINTPTR)pVM;
|
|
|
|
pVM->pSession = req.pSession;
|
|
|
|
pVM->cbSelf = cbVM;
|
|
|
|
pVM->cCpus = cCpus;
|
|
|
|
pVM->uCpuExecutionCap = 100; /* expected by 'vmR3CreateU()' */
|
|
|
|
pVM->offVMCPU = RT_UOFFSETOF(VM, aCpus);
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < cCpus; i++) {
|
|
|
|
pVM->aCpus[i].pVMR0 = pVM->pVMR0;
|
|
|
|
pVM->aCpus[i].pVMR3 = pVM;
|
|
|
|
pVM->aCpus[i].idHostCpu = NIL_RTCPUID;
|
|
|
|
pVM->aCpus[i].hNativeThreadR0 = NIL_RTNATIVETHREAD;
|
|
|
|
}
|
|
|
|
|
|
|
|
pVM->aCpus[0].hNativeThreadR0 = RTThreadNativeSelf();
|
|
|
|
|
|
|
|
/* out parameters of the request */
|
|
|
|
req.pVMR0 = pVM->pVMR0;
|
|
|
|
req.pVMR3 = pVM;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void genode_VMMR0_DO_GVMM_REGISTER_VMCPU(PVMR0 pVMR0, VMCPUID idCpu)
|
|
|
|
{
|
|
|
|
PVM pVM = reinterpret_cast<PVM>(pVMR0);
|
|
|
|
pVM->aCpus[idCpu].hNativeThreadR0 = RTThreadNativeSelf();
|
|
|
|
}
|