cpu, mem, sim: Change how KVM maps memory
authorDavid Hashe <david.j.hashe@gmail.com>
Mon, 22 Aug 2016 15:41:05 +0000 (11:41 -0400)
committerDavid Hashe <david.j.hashe@gmail.com>
Mon, 22 Aug 2016 15:41:05 +0000 (11:41 -0400)
Only map memories into the KVM guest address space that are
marked as usable by KVM. Create BackingStoreEntry class
containing flags for is_conf_reported, in_addr_map, and
kvm_map.

src/cpu/kvm/vm.cc
src/mem/AbstractMemory.py
src/mem/abstract_mem.cc
src/mem/abstract_mem.hh
src/mem/physical.cc
src/mem/physical.hh

index ccf739305b60766bc725ad163dbe90510997792b..39bce32f45befef6709fd4f69933227ebc401e35 100644 (file)
@@ -341,13 +341,18 @@ KvmVM::cpuStartup()
 void
 KvmVM::delayedStartup()
 {
-    const std::vector<std::pair<AddrRange, uint8_t*> >&memories(
+    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",
index ab1a6028c587f2f14430db772d64dae00e4c41e5..d5b34bbd07007c7d1834b6cce43e89c2c622f04b 100644 (file)
@@ -57,6 +57,12 @@ class AbstractMemory(MemObject):
     # e.g. by the testers that use shadow memories as a reference
     in_addr_map = Param.Bool(True, "Memory part of the global address map")
 
+    # When KVM acceleration is used, memory is mapped into the guest process
+    # address space and accessed directly. Some memories may need to be
+    # excluded from this mapping if they overlap with other memory ranges or
+    # are not accessible by the CPU.
+    kvm_map = Param.Bool(True, "Should KVM map this memory for the guest")
+
     # Should the bootloader include this memory when passing
     # configuration information about the physical memory layout to
     # the kernel, e.g. using ATAG or ACPI
index 04e4b00574f6b8878655629049a458ed55ba4d0d..1797deae83c0b8a265036090236e14c7e4ee4a4b 100644 (file)
@@ -57,7 +57,7 @@ using namespace std;
 AbstractMemory::AbstractMemory(const Params *p) :
     MemObject(p), range(params()->range), pmemAddr(NULL),
     confTableReported(p->conf_table_reported), inAddrMap(p->in_addr_map),
-    _system(NULL)
+    kvmMap(p->kvm_map), _system(NULL)
 {
 }
 
index 8ab28770d18b78fdd5979f6a3f8edf095766c801..31d34f051bd1091e133c0bfb6b76b1748b0d3026 100644 (file)
@@ -111,10 +111,13 @@ class AbstractMemory : public MemObject
     uint8_t* pmemAddr;
 
     // Enable specific memories to be reported to the configuration table
-    bool confTableReported;
+    const bool confTableReported;
 
     // Should the memory appear in the global address map
-    bool inAddrMap;
+    const bool inAddrMap;
+
+    // Should KVM map this memory for the guest
+    const bool kvmMap;
 
     std::list<LockedAddr> lockedAddrList;
 
@@ -282,6 +285,14 @@ class AbstractMemory : public MemObject
      */
     bool isInAddrMap() const { return inAddrMap; }
 
+    /**
+     * When shadow memories are in use, KVM may want to make one or the other,
+     * but cannot map both into the guest address space.
+     *
+     * @return if this memory should be mapped into the KVM guest address space
+     */
+    bool isKvmMap() const { return kvmMap; }
+
     /**
      * Perform an untimed memory access and update all the state
      * (e.g. locked addresses) and statistics accordingly. The packet
index 82e331fe11d81fd3ec92e5e74f4040a46c22b96e..05881b2248a76b05c62b5bf182501ba30c0398a5 100644 (file)
@@ -111,7 +111,9 @@ PhysicalMemory::PhysicalMemory(const string& _name,
             // memories are allowed to overlap in the logic address
             // map
             vector<AbstractMemory*> unmapped_mems{m};
-            createBackingStore(m->getAddrRange(), unmapped_mems);
+            createBackingStore(m->getAddrRange(), unmapped_mems,
+                               m->isConfReported(), m->isInAddrMap(),
+                               m->isKvmMap());
         }
     }
 
@@ -132,7 +134,19 @@ PhysicalMemory::PhysicalMemory(const string& _name,
                 if (!intlv_ranges.empty() &&
                     !intlv_ranges.back().mergesWith(r.first)) {
                     AddrRange merged_range(intlv_ranges);
-                    createBackingStore(merged_range, curr_memories);
+
+                    AbstractMemory *f = curr_memories.front();
+                    for (const auto& c : curr_memories)
+                        if (f->isConfReported() != c->isConfReported() ||
+                            f->isInAddrMap() != c->isInAddrMap() ||
+                            f->isKvmMap() != c->isKvmMap())
+                            fatal("Inconsistent flags in an interleaved "
+                                  "range\n");
+
+                    createBackingStore(merged_range, curr_memories,
+                                       f->isConfReported(), f->isInAddrMap(),
+                                       f->isKvmMap());
+
                     intlv_ranges.clear();
                     curr_memories.clear();
                 }
@@ -140,7 +154,10 @@ PhysicalMemory::PhysicalMemory(const string& _name,
                 curr_memories.push_back(r.second);
             } else {
                 vector<AbstractMemory*> single_memory{r.second};
-                createBackingStore(r.first, single_memory);
+                createBackingStore(r.first, single_memory,
+                                   r.second->isConfReported(),
+                                   r.second->isInAddrMap(),
+                                   r.second->isKvmMap());
             }
         }
     }
@@ -149,13 +166,26 @@ PhysicalMemory::PhysicalMemory(const string& _name,
     // ahead and do it
     if (!intlv_ranges.empty()) {
         AddrRange merged_range(intlv_ranges);
-        createBackingStore(merged_range, curr_memories);
+
+        AbstractMemory *f = curr_memories.front();
+        for (const auto& c : curr_memories)
+            if (f->isConfReported() != c->isConfReported() ||
+                f->isInAddrMap() != c->isInAddrMap() ||
+                f->isKvmMap() != c->isKvmMap())
+                fatal("Inconsistent flags in an interleaved "
+                      "range\n");
+
+        createBackingStore(merged_range, curr_memories,
+                           f->isConfReported(), f->isInAddrMap(),
+                           f->isKvmMap());
     }
 }
 
 void
 PhysicalMemory::createBackingStore(AddrRange range,
-                                   const vector<AbstractMemory*>& _memories)
+                                   const vector<AbstractMemory*>& _memories,
+                                   bool conf_table_reported,
+                                   bool in_addr_map, bool kvm_map)
 {
     panic_if(range.interleaved(),
              "Cannot create backing store for interleaved range %s\n",
@@ -184,7 +214,8 @@ PhysicalMemory::createBackingStore(AddrRange range,
 
     // remember this backing store so we can checkpoint it and unmap
     // it appropriately
-    backingStore.push_back(make_pair(range, pmem));
+    backingStore.emplace_back(range, pmem,
+                              conf_table_reported, in_addr_map, kvm_map);
 
     // point the memories to their backing store
     for (const auto& m : _memories) {
@@ -198,7 +229,7 @@ PhysicalMemory::~PhysicalMemory()
 {
     // unmap the backing store
     for (auto& s : backingStore)
-        munmap((char*)s.second, s.first.size());
+        munmap((char*)s.pmem, s.range.size());
 }
 
 bool
@@ -314,7 +345,7 @@ PhysicalMemory::serialize(CheckpointOut &cp) const
     // store each backing store memory segment in a file
     for (auto& s : backingStore) {
         ScopedCheckpointSection sec(cp, csprintf("store%d", store_id));
-        serializeStore(cp, store_id++, s.first, s.second);
+        serializeStore(cp, store_id++, s.range, s.pmem);
     }
 }
 
@@ -407,8 +438,8 @@ PhysicalMemory::unserializeStore(CheckpointIn &cp)
         fatal("Can't open physical memory checkpoint file '%s'", filename);
 
     // we've already got the actual backing store mapped
-    uint8_t* pmem = backingStore[store_id].second;
-    AddrRange range = backingStore[store_id].first;
+    uint8_t* pmem = backingStore[store_id].pmem;
+    AddrRange range = backingStore[store_id].range;
 
     long range_size;
     UNSERIALIZE_SCALAR(range_size);
index 7f4c975f05e05441c241db42e06adb48d16e43b4..cc733b2d67d14bb6d34bbfcf10de98d3a2c442c6 100644 (file)
  */
 class AbstractMemory;
 
+/**
+ * A single entry for the backing store.
+ */
+class BackingStoreEntry
+{
+  public:
+
+    /**
+     * Create a backing store entry. Don't worry about managing the memory
+     * pointers, because PhysicalMemory is responsible for that.
+     */
+    BackingStoreEntry(AddrRange range, uint8_t* pmem,
+                      bool conf_table_reported, bool in_addr_map, bool kvm_map)
+        : range(range), pmem(pmem), confTableReported(conf_table_reported),
+          inAddrMap(in_addr_map), kvmMap(kvm_map)
+        {}
+
+    /**
+     * The address range covered in the guest.
+     */
+     AddrRange range;
+
+    /**
+     * Pointer to the host memory this range maps to. This memory is the same
+     * size as the range field.
+     */
+     uint8_t* pmem;
+
+     /**
+      * Whether this memory should be reported to the configuration table
+      */
+     bool confTableReported;
+
+     /**
+      * Whether this memory should appear in the global address map
+      */
+     bool inAddrMap;
+
+     /**
+      * Whether KVM should map this memory into the guest address space during
+      * acceleration.
+      */
+     bool kvmMap;
+};
+
 /**
  * The physical memory encapsulates all memories in the system and
  * provides basic functionality for accessing those memories without
@@ -90,7 +135,7 @@ class PhysicalMemory : public Serializable
 
     // The physical memory used to provide the memory in the simulated
     // system
-    std::vector<std::pair<AddrRange, uint8_t*>> backingStore;
+    std::vector<BackingStoreEntry> backingStore;
 
     // Prevent copying
     PhysicalMemory(const PhysicalMemory&);
@@ -105,9 +150,12 @@ class PhysicalMemory : public Serializable
      *
      * @param range The address range covered
      * @param memories The memories this range maps to
+     * @param kvm_map Should KVM map this memory for the guest
      */
     void createBackingStore(AddrRange range,
-                            const std::vector<AbstractMemory*>& _memories);
+                            const std::vector<AbstractMemory*>& _memories,
+                            bool conf_table_reported,
+                            bool in_addr_map, bool kvm_map);
 
   public:
 
@@ -167,7 +215,7 @@ class PhysicalMemory : public Serializable
      *
      * @return Pointers to the memory backing store
      */
-    std::vector<std::pair<AddrRange, uint8_t*>> getBackingStore() const
+    std::vector<BackingStoreEntry> getBackingStore() const
     { return backingStore; }
 
     /**