From 70eb68beae90c6f27ca3c45cfd3f53531e548cb4 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Tue, 9 Dec 2014 21:53:44 -0800 Subject: [PATCH] Let other objects set up memory like regions in a KVM VM. --- src/cpu/kvm/vm.cc | 80 +++++++++++++++++++++++++++++++++++++++++------ src/cpu/kvm/vm.hh | 60 ++++++++++++++++++++++++++++++++--- 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::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 * @@ -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 memorySlots; + uint32_t maxMemorySlot; }; #endif -- 2.30.2