genode/repos/ports/src/virtualbox/iommio.cc

206 lines
5.2 KiB
C++

/*
* \brief VirtualBox Memory-mapped I/O monitor
* \author Norman Feske
* \date 2013-09-02
*/
/*
* Copyright (C) 2013 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode includes */
#include <base/printf.h>
/* VirtualBox includes */
#include "IOMInternal.h"
#include <VBox/vmm/vm.h>
#include <VBox/vmm/iom.h>
#include <VBox/vmm/rem.h>
/* local includes */
#include "guest_memory.h"
static const bool verbose = false;
VMMR3_INT_DECL(int) IOMR3Init(PVM pVM)
{
/*
* Assert alignment and sizes.
*/
AssertCompileMemberAlignment(VM, iom.s, 32);
AssertCompile(sizeof(pVM->iom.s) <= sizeof(pVM->iom.padding));
AssertCompileMemberAlignment(IOM, CritSect, sizeof(uintptr_t));
/*
* Initialize the REM critical section.
*/
#ifdef IOM_WITH_CRIT_SECT_RW
int rc = PDMR3CritSectRwInit(pVM, &pVM->iom.s.CritSect, RT_SRC_POS, "IOM Lock");
#else
int rc = PDMR3CritSectInit(pVM, &pVM->iom.s.CritSect, RT_SRC_POS, "IOM Lock");
#endif
AssertRCReturn(rc, rc);
return VINF_SUCCESS;
}
int IOMR3Term(PVM)
{
if (verbose)
PDBG("called");
return VINF_SUCCESS;
}
VMMDECL(bool) IOMIsLockWriteOwner(PVM pVM)
{
#ifdef IOM_WITH_CRIT_SECT_RW
return PDMCritSectRwIsInitialized(&pVM->iom.s.CritSect)
&& PDMCritSectRwIsWriteOwner(&pVM->iom.s.CritSect);
#else
return PDMCritSectIsOwner(&pVM->iom.s.CritSect);
#endif
}
int IOMR3MmioRegisterR3(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart,
uint32_t cbRange, RTHCPTR pvUser,
R3PTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallback,
R3PTRTYPE(PFNIOMMMIOREAD) pfnReadCallback,
R3PTRTYPE(PFNIOMMMIOFILL) pfnFillCallback,
uint32_t fFlags, const char *pszDesc)
{
if (verbose)
PLOG("%s: GCPhys=0x%llx cb=0x%x pszDesc=%s rd=%p wr=%p fl=%p flags=%x",
__PRETTY_FUNCTION__,
(Genode::uint64_t)GCPhysStart, cbRange, pszDesc,
pfnWriteCallback, pfnReadCallback, pfnFillCallback, fFlags);
REMR3NotifyHandlerPhysicalRegister(pVM, PGMPHYSHANDLERTYPE_MMIO,
GCPhysStart, cbRange, true);
guest_memory()->add_mmio_mapping(GCPhysStart, cbRange,
pDevIns, pvUser, pfnWriteCallback,
pfnReadCallback, pfnFillCallback, fFlags);
return VINF_SUCCESS;
}
int IOMR3MmioDeregister(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart,
uint32_t cbRange)
{
if (verbose)
PLOG("%s: GCPhys=0x%llx cb=0x%x", __PRETTY_FUNCTION__,
(Genode::uint64_t)GCPhysStart, cbRange);
bool status = guest_memory()->remove_mmio_mapping(GCPhysStart, cbRange);
if (status)
return VINF_SUCCESS;
return !VINF_SUCCESS;
}
VMMDECL(VBOXSTRICTRC) IOMMMIOWrite(PVM pVM, PVMCPU, RTGCPHYS GCPhys,
uint32_t u32Value, size_t cbValue)
{
VBOXSTRICTRC rc = IOM_LOCK_SHARED(pVM);
Assert(rc == VINF_SUCCESS);
rc = guest_memory()->mmio_write(GCPhys, u32Value, cbValue);
/*
* Check whether access is unaligned or access width is less than device
* supports. See original IOMMMIOWrite & iomMMIODoComplicatedWrite of VBox.
*/
if (rc == VERR_IOM_NOT_MMIO_RANGE_OWNER) {
Assert(cbValue <= 4);
uint32_t value;
RTGCPHYS aligned = GCPhys & ~0x3U;
rc = guest_memory()->mmio_read(aligned, &value, sizeof(value));
uint32_t offset = GCPhys & 0x3;
memcpy(((char *)&value) + offset, &u32Value, cbValue);
rc = guest_memory()->mmio_write(aligned, value, sizeof(value));
}
Assert(rc != VERR_IOM_NOT_MMIO_RANGE_OWNER);
IOM_UNLOCK_SHARED(pVM);
return rc;
}
VMMDECL(VBOXSTRICTRC) IOMMMIORead(PVM pVM, PVMCPU, RTGCPHYS GCPhys,
uint32_t *pvalue, size_t bytes)
{
VBOXSTRICTRC rc = IOM_LOCK_SHARED(pVM);
Assert(rc == VINF_SUCCESS);
rc = guest_memory()->mmio_read(GCPhys, pvalue, bytes);
/*
* Check whether access is unaligned or access width is less than device
* supports. See original IOMMMIORead & iomMMIODoComplicatedRead of VBox.
*/
if (rc == VERR_IOM_NOT_MMIO_RANGE_OWNER) {
/* implement what we need to - extend by need */
Assert(bytes == 1 || bytes == 2);
uint32_t value = 0;
if ((GCPhys & 3UL) == 0)
rc = guest_memory()->mmio_read(GCPhys, &value, sizeof(value));
else {
/* only read until word boundary */
Assert(((GCPhys & 3UL) + bytes) <= sizeof(value));
/*
* Do an aligned read and shift the result to get the value at
* the unaligned address.
*/
rc = guest_memory()->mmio_read((GCPhys & ~3UL), &value, sizeof(value));
value >>= (8 * (GCPhys & 3UL));
}
Assert(rc == VINF_SUCCESS);
if (rc == VINF_SUCCESS) {
switch (bytes) {
case 1:
*(uint8_t *) pvalue = (uint8_t)value;
case 2:
*(uint16_t *)pvalue = (uint16_t)value;
}
}
}
IOM_UNLOCK_SHARED(pVM);
return rc;
}
int IOMMMIOMapMMIO2Page(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysRemapped,
uint64_t fPageFlags)
{
if (verbose)
PDBG("called - %llx %llx", (Genode::uint64_t)GCPhys,
(Genode::uint64_t)GCPhysRemapped);
return VINF_SUCCESS;
}
int IOMMMIOResetRegion(PVM pVM, RTGCPHYS GCPhys)
{
if (verbose)
PDBG("called - %llx", (Genode::uint64_t)GCPhys);
return VINF_SUCCESS;
}