GIMKvm.cpp revision 9c178a84047ec38c02debb747cbdc7de4531d940
/* $Id$ */
/** @file
* GIM - Guest Interface Manager, KVM implementation.
*/
/*
* Copyright (C) 2015 Oracle Corporation
*
* 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.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_GIM
#include "GIMInternal.h"
#include <iprt/asm-math.h>
#include <iprt/spinlock.h>
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/**
* GIM KVM saved-state version.
*/
/*******************************************************************************
* Global Variables *
*******************************************************************************/
#ifdef VBOX_WITH_STATISTICS
{ (a_uFirst), (a_uLast), kCpumMsrRdFn_Gim, kCpumMsrWrFn_Gim, 0, 0, 0, 0, 0, a_szName, { 0 }, { 0 }, { 0 }, { 0 } }
#else
#endif
/**
* Array of MSR ranges supported by KVM.
*/
static CPUMMSRRANGE const g_aMsrRanges_Kvm[] =
{
};
/**
* Initializes the KVM GIM provider.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
* @param uVersion The interface version this VM should use.
*/
{
int rc;
/*
* Determine interface capabilities based on the version.
*/
{
/* Basic features. */
//| GIM_KVM_BASE_FEAT_NOP_IO_DELAY
//| GIM_KVM_BASE_FEAT_MMU_OP
//| GIM_KVM_BASE_FEAT_ASYNC_PF
//| GIM_KVM_BASE_FEAT_STEAL_TIME
//| GIM_KVM_BASE_FEAT_PV_EOI
;
/* Rest of the features are determined in gimR3KvmInitCompleted(). */
}
/*
* Expose HVP (Hypervisor Present) bit to the guest.
*/
/*
* Modify the standard hypervisor leaves for KVM.
*/
/*
* Add KVM specific leaves.
*/
/*
* Insert all MSR ranges of KVM.
*/
for (unsigned i = 0; i < RT_ELEMENTS(g_aMsrRanges_Kvm); i++)
{
}
return VINF_SUCCESS;
}
/**
* Initializes remaining bits of the KVM provider.
*
* This is called after initializing HM and almost all other VMM components.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
*/
{
{
}
return VINF_SUCCESS;
}
/**
* Terminates the KVM GIM provider.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
*/
{
return VINF_SUCCESS;
}
/**
* Applies relocations to data and code managed by this component.
*
* This function will be called at init and whenever the VMM need to relocate
* itself inside the GC.
*
* @param pVM Pointer to the VM.
* @param offDelta Relocation delta relative to old location.
*/
{
}
/**
* This resets KVM provider MSRs and unmaps whatever KVM regions that
* the guest may have mapped.
*
* This is called when the VM is being reset.
*
* @param pVM Pointer to the VM.
* @thread EMT(0).
*/
{
/*
* Reset MSRs.
*/
pKvm->u64WallClockMsr = 0;
{
pKvmCpu->u64SystemTimeMsr = 0;
}
}
/**
* KVM state-save operation.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
* @param pSSM Pointer to the SSM handle.
*/
{
/*
* Save the KVM SSM version.
*/
/*
* Save per-VCPU data.
*/
{
/* Guest may alter flags (namely GIM_KVM_SYSTEM_TIME_FLAGS_GUEST_PAUSED bit). So re-read them from guest-memory. */
{
int rc = PGMPhysSimpleReadGCPhys(pVM, &SystemTime, pcKvmCpu->GCPhysSystemTime, sizeof(GIMKVMSYSTEMTIME));
}
}
/*
* Save per-VM data.
*/
}
/**
* KVM state-load operation, final pass.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
* @param pSSM Pointer to the SSM handle.
* @param uSSMVersion The GIM saved-state version.
*/
{
/*
* Load the KVM SSM version first.
*/
/*
* Load per-VCPU data.
*/
{
uint8_t fSystemTimeFlags = 0;
/* Enable the system-time struct. if necessary. */
{
}
}
/*
* Load per-VM data.
*/
return VINF_SUCCESS;
}
/**
* Enables the KVM VCPU system-time structure.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
* @param pVCpu Pointer to the VMCPU.
* @param pKvmCpu Pointer to the GIMKVMCPU with all fields
* populated by the caller.
* @param fFlags The system-time struct. flags.
*
* @remarks Don't do any release assertions here, these can be triggered by
* guest R0 code.
*/
VMMR3_INT_DECL(int) gimR3KvmEnableSystemTime(PVM pVM, PVMCPU pVCpu, PGIMKVMCPU pKvmCpu, uint8_t fFlags)
{
/*
* How the guest calculates the system time (nanoseconds):
*
* tsc = rdtsc - SysTime.u64Tsc
* if (SysTime.i8TscShift >= 0)
* tsc <<= i8TscShift;
* else
* tsc >>= -i8TscShift;
* time = ((tsc * SysTime.u32TscScale) >> 32) + SysTime.u64NanoTS
*/
SystemTime.i8TscShift = 0;
{
u64TscFreq >>= 1;
}
while (uTscFreqLo <= RT_NS_1SEC)
{
uTscFreqLo <<= 1;
}
int rc = PGMPhysSimpleWriteGCPhys(pVM, pKvmCpu->GCPhysSystemTime, &SystemTime, sizeof(GIMKVMSYSTEMTIME));
if (RT_SUCCESS(rc))
{
LogRel(("GIM: KVM: VCPU%3d: Enabled system-time struct. at %#RGp - u32TscScale=%#RX32 i8TscShift=%d uVersion=%#RU32 "
"fFlags=%#x uTsc=%#RX64 uVirtNanoTS=%#RX64\n", pVCpu->idCpu, pKvmCpu->GCPhysSystemTime, SystemTime.u32TscScale,
SystemTime.i8TscShift, SystemTime.u32Version, SystemTime.fFlags, pKvmCpu->uTsc, pKvmCpu->uVirtNanoTS));
}
else
LogRel(("GIM: KVM: VCPU%3d: Failed to write system-time struct. at %#RGp. rc=%Rrc\n", pKvmCpu->GCPhysSystemTime, rc));
return rc;
}
/**
* Disables the KVM system-time struct.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
*/
{
return VINF_SUCCESS;
}
/**
* Enables the KVM wall-clock structure.
*
* @returns VBox status code.
* @param pVM Pointer to the VM.
* @param GCPhysWallClock Where the guest wall-clock structure is located.
* @param uVersion The version (sequence number) value to use.
*
* @remarks Don't do any release assertions here, these can be triggered by
* guest R0 code.
*/
{
if (RT_SUCCESS(rc))
{
LogRel(("GIM: KVM: Enabled wall-clock struct. at %#RGp - u32Sec=%u u32Nano=%u uVersion=%#RU32\n", GCPhysWallClock,
}
else
return rc;
}