summaryrefslogtreecommitdiff
path: root/src/cpu/kvm
diff options
context:
space:
mode:
authorGabe Black <gabeblack@google.com>2014-12-09 21:53:44 -0800
committerGabe Black <gabeblack@google.com>2014-12-09 21:53:44 -0800
commit70eb68beae90c6f27ca3c45cfd3f53531e548cb4 (patch)
treea77790060fb50d8b7d3b39d1fa6c12d67f3e7a62 /src/cpu/kvm
parent9b7578d8c7f82e255776a354657d1f19f1ca64f4 (diff)
downloadgem5-70eb68beae90c6f27ca3c45cfd3f53531e548cb4.tar.xz
Let other objects set up memory like regions in a KVM VM.
Diffstat (limited to 'src/cpu/kvm')
-rw-r--r--src/cpu/kvm/vm.cc80
-rw-r--r--src/cpu/kvm/vm.hh60
2 files changed, 127 insertions, 13 deletions
diff --git a/src/cpu/kvm/vm.cc b/src/cpu/kvm/vm.cc
index 5ce42a5ac..4ef11b2ee 100644
--- a/src/cpu/kvm/vm.cc
+++ b/src/cpu/kvm/vm.cc
@@ -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()
}
}
+const KvmVM::MemSlot
+KvmVM::allocMemSlot(uint64_t size)
+{
+ if (!size)
+ panic("Memory slots must have non-zero size.\n");
+
+ 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::setUserMemoryRegion(uint32_t slot,
- void *host_addr, AddrRange guest_range,
- uint32_t flags)
+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)
{
- if (guest_range.interleaved())
- panic("Tried to map an interleaved memory range into a KVM VM.\n");
+ MemorySlot &slot = memorySlots.at(num.num);
+ if (slot.active)
+ setUserMemoryRegion(num.num, NULL, 0, 0, 0);
+ slot.active = false;
+}
- setUserMemoryRegion(slot, host_addr,
- guest_range.start(), guest_range.size(),
- flags);
+void
+KvmVM::freeMemSlot(const KvmVM::MemSlot num)
+{
+ disableMemSlot(num.num);
+ MemorySlot &slot = memorySlots.at(num.num);
+ slot.size = 0;
}
void
diff --git a/src/cpu/kvm/vm.hh b/src/cpu/kvm/vm.hh
index 660805ed7..84d526705 100644
--- a/src/cpu/kvm/vm.hh
+++ b/src/cpu/kvm/vm.hh
@@ -1,4 +1,5 @@
/*
+ * Copyright 2014 Google, Inc.
* Copyright (c) 2012 ARM Limited
* All rights reserved
*
@@ -110,6 +111,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.
*
* @see BaseKvmCPU::getOneReg(), and BaseKvmCPU::setOneReg()
@@ -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