Let other objects set up memory like regions in a KVM VM.

This commit is contained in:
Gabe Black 2014-12-09 21:53:44 -08:00
parent 9b7578d8c7
commit 70eb68beae
2 changed files with 128 additions and 14 deletions

View file

@ -1,4 +1,5 @@
/*
* Copyright 2014 Google, Inc.
* Copyright (c) 2012 ARM Limited
* All rights reserved
*
@ -124,6 +125,16 @@ Kvm::capCoalescedMMIO() const
return checkExtension(KVM_CAP_COALESCED_MMIO);
}
int
Kvm::capNumMemSlots() const
{
#ifdef KVM_CAP_NR_MEMSLOTS
return checkExtension(KVM_CAP_NR_MEMSLOTS);
#else
return 0;
#endif
}
bool
Kvm::capOneReg() const
{
@ -288,6 +299,10 @@ KvmVM::KvmVM(KvmVMParams *params)
started(false),
nextVCPUID(0)
{
maxMemorySlot = kvm.capNumMemSlots();
/* If we couldn't determine how memory slots there are, guess 32. */
if (!maxMemorySlot)
maxMemorySlot = 32;
/* Setup the coalesced MMIO regions */
for (int i = 0; i < params->coalescedMMIO.size(); ++i)
coalesceMMIO(params->coalescedMMIO[i]);
@ -323,7 +338,13 @@ KvmVM::delayedStartup()
DPRINTF(Kvm, "Mapping region: 0x%p -> 0x%llx [size: 0x%llx]\n",
pmem, range.start(), range.size());
setUserMemoryRegion(slot, pmem, range, 0 /* flags */);
if (range.interleaved()) {
panic("Tried to map an interleaved memory range into "
"a KVM VM.\n");
}
const MemSlot slot = allocMemSlot(range.size());
setupMemSlot(slot, pmem, range.start(), 0/* flags */);
} else {
DPRINTF(Kvm, "Zero-region not mapped: [0x%llx]\n", range.start());
hack("KVM: Zero memory handled as IO\n");
@ -331,17 +352,58 @@ KvmVM::delayedStartup()
}
}
void
KvmVM::setUserMemoryRegion(uint32_t slot,
void *host_addr, AddrRange guest_range,
uint32_t flags)
const KvmVM::MemSlot
KvmVM::allocMemSlot(uint64_t size)
{
if (guest_range.interleaved())
panic("Tried to map an interleaved memory range into a KVM VM.\n");
if (!size)
panic("Memory slots must have non-zero size.\n");
setUserMemoryRegion(slot, host_addr,
guest_range.start(), guest_range.size(),
flags);
std::vector<MemorySlot>::iterator pos;
for (pos = memorySlots.begin(); pos != memorySlots.end(); pos++) {
if (!pos->size) {
pos->size = size;
pos->active = false;
return pos->slot;
}
}
uint32_t nextSlot = memorySlots.size();
if (nextSlot > maxMemorySlot)
panic("Out of memory slots.\n");
MemorySlot slot;
slot.size = size;
slot.slot = nextSlot;
slot.active = false;
memorySlots.push_back(slot);
return MemSlot(slot.slot);
}
void
KvmVM::setupMemSlot(const KvmVM::MemSlot num, void *host_addr, Addr guest,
uint32_t flags)
{
MemorySlot &slot = memorySlots.at(num.num);
slot.active = true;
setUserMemoryRegion(num.num, host_addr, guest, slot.size, flags);
}
void
KvmVM::disableMemSlot(const KvmVM::MemSlot num)
{
MemorySlot &slot = memorySlots.at(num.num);
if (slot.active)
setUserMemoryRegion(num.num, NULL, 0, 0, 0);
slot.active = false;
}
void
KvmVM::freeMemSlot(const KvmVM::MemSlot num)
{
disableMemSlot(num.num);
MemorySlot &slot = memorySlots.at(num.num);
slot.size = 0;
}
void

View file

@ -1,4 +1,5 @@
/*
* Copyright 2014 Google, Inc.
* Copyright (c) 2012 ARM Limited
* All rights reserved
*
@ -109,6 +110,12 @@ class Kvm
*/
int capCoalescedMMIO() const;
/**
* Attempt to determine how many memory slots are available. If it can't
* be determined, this function returns 0.
*/
int capNumMemSlots() const;
/**
* Support for reading and writing single registers.
*
@ -331,6 +338,42 @@ class KvmVM : public SimObject
bool hasKernelIRQChip() const { return _hasKernelIRQChip; }
/** @} */
struct MemSlot
{
MemSlot(uint32_t _num) : num(_num)
{}
MemSlot() : num(-1)
{}
int32_t num;
};
/**
* Allocate a memory slot within the VM.
*/
const MemSlot allocMemSlot(uint64_t size);
/**
* Setup a region of physical memory in the guest
*
* @param slot KVM memory slot ID returned by allocMemSlot
* @param host_addr Memory allocation backing the memory
* @param guest_addr Address in the guest
* @param flags Flags (see the KVM API documentation)
*/
void setupMemSlot(const MemSlot slot, void *host_addr, Addr guest_addr,
uint32_t flags);
/**
* Disable a memory slot.
*/
void disableMemSlot(const MemSlot slot);
/**
* Free a previously allocated memory slot.
*/
void freeMemSlot(const MemSlot slot);
/** Global KVM interface */
Kvm kvm;
@ -366,16 +409,12 @@ class KvmVM : public SimObject
* @param slot KVM memory slot ID (must be unique)
* @param host_addr Memory allocation backing the memory
* @param guest_addr Address in the guest
* @param guest_range Address range used by guest.
* @param len Size of the allocation in bytes
* @param flags Flags (see the KVM API documentation)
*/
void setUserMemoryRegion(uint32_t slot,
void *host_addr, Addr guest_addr,
uint64_t len, uint32_t flags);
void setUserMemoryRegion(uint32_t slot,
void *host_addr, AddrRange guest_range,
uint32_t flags);
/** @} */
/**
@ -437,6 +476,19 @@ class KvmVM : public SimObject
/** Next unallocated vCPU ID */
long nextVCPUID;
/**
* Structures tracking memory slots.
*/
class MemorySlot
{
public:
uint64_t size;
uint32_t slot;
bool active;
};
std::vector<MemorySlot> memorySlots;
uint32_t maxMemorySlot;
};
#endif