sim, kvm: make KvmVM a System parameter
[gem5.git] / src / cpu / kvm / vm.cc
index 01670fab40e01bcd72a2c221987c79162c4e7a37..604d182ab2e5fe0057bbe9dfe42956f9aa04af42 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright 2014 Google, Inc.
- * Copyright (c) 2012 ARM Limited
+ * Copyright (c) 2012, 2015 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
  * Authors: Andreas Sandberg
  */
 
+#include "cpu/kvm/vm.hh"
+
+#include <fcntl.h>
 #include <linux/kvm.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <fcntl.h>
 #include <unistd.h>
 
 #include <cerrno>
 #include <memory>
 
-#include "cpu/kvm/vm.hh"
 #include "debug/Kvm.hh"
 #include "params/KvmVM.hh"
 #include "sim/system.hh"
@@ -291,12 +292,12 @@ Kvm::createVM()
 
 KvmVM::KvmVM(KvmVMParams *params)
     : SimObject(params),
-      kvm(), system(params->system),
-      vmFD(kvm.createVM()),
+      kvm(new Kvm()), system(nullptr),
+      vmFD(kvm->createVM()),
       started(false),
       nextVCPUID(0)
 {
-    maxMemorySlot = kvm.capNumMemSlots();
+    maxMemorySlot = kvm->capNumMemSlots();
     /* If we couldn't determine how memory slots there are, guess 32. */
     if (!maxMemorySlot)
         maxMemorySlot = 32;
@@ -307,7 +308,25 @@ KvmVM::KvmVM(KvmVMParams *params)
 
 KvmVM::~KvmVM()
 {
-    close(vmFD);
+    if (vmFD != -1)
+        close(vmFD);
+
+    if (kvm)
+        delete kvm;
+}
+
+void
+KvmVM::notifyFork()
+{
+    if (vmFD != -1) {
+        if (close(vmFD) == -1)
+            warn("kvm VM: notifyFork failed to close vmFD\n");
+
+        vmFD = -1;
+
+        delete kvm;
+        kvm = NULL;
+    }
 }
 
 void
@@ -323,13 +342,19 @@ KvmVM::cpuStartup()
 void
 KvmVM::delayedStartup()
 {
-    const std::vector<std::pair<AddrRange, uint8_t*> >&memories(
+    assert(system); // set by the system during its construction
+    const std::vector<BackingStoreEntry> &memories(
         system->getPhysMem().getBackingStore());
 
     DPRINTF(Kvm, "Mapping %i memory region(s)\n", memories.size());
     for (int slot(0); slot < memories.size(); ++slot) {
-        const AddrRange &range(memories[slot].first);
-        void *pmem(memories[slot].second);
+        if (!memories[slot].kvmMap) {
+            DPRINTF(Kvm, "Skipping region marked as not usable by KVM\n");
+            continue;
+        }
+
+        const AddrRange &range(memories[slot].range);
+        void *pmem(memories[slot].pmem);
 
         if (pmem) {
             DPRINTF(Kvm, "Mapping region: 0x%p -> 0x%llx [size: 0x%llx]\n",
@@ -485,6 +510,30 @@ KvmVM::setIRQLine(uint32_t irq, bool high)
               errno);
 }
 
+int
+KvmVM::createDevice(uint32_t type, uint32_t flags)
+{
+#if defined(KVM_CREATE_DEVICE)
+    struct kvm_create_device dev = { type, 0, flags };
+
+    if (ioctl(KVM_CREATE_DEVICE, &dev) == -1) {
+        panic("KVM: Failed to create device (errno: %i)\n",
+              errno);
+    }
+
+    return dev.fd;
+#else
+    panic("Kernel headers don't support KVM_CREATE_DEVICE\n");
+#endif
+}
+
+void
+KvmVM::setSystem(System *s) {
+    panic_if(system != nullptr, "setSystem() can only be called once");
+    panic_if(s == nullptr, "setSystem() called with null System*");
+    system = s;
+}
+
 int
 KvmVM::createVCPU(long vcpuID)
 {
@@ -503,6 +552,17 @@ KvmVM::allocVCPUID()
     return nextVCPUID++;
 }
 
+#if defined(__aarch64__)
+void
+KvmVM::kvmArmPreferredTarget(struct kvm_vcpu_init &target) const
+{
+    if (ioctl(KVM_ARM_PREFERRED_TARGET, &target) == -1) {
+        panic("KVM: Failed to get ARM preferred CPU target (errno: %i)\n",
+              errno);
+    }
+}
+#endif
+
 int
 KvmVM::ioctl(int request, long p1) const
 {