mem: Support initializing a memory with an image file.
authorGabe Black <gabeblack@google.com>
Sun, 29 Mar 2020 10:14:50 +0000 (03:14 -0700)
committerGabe Black <gabeblack@google.com>
Thu, 16 Apr 2020 23:43:08 +0000 (23:43 +0000)
This is particularly useful for ROMs. It avoids forcing other components
of the simulation (the System object, the Workload object) from having
to know what ROMs exist, where they are, and what goes on them, and
leaves that to the config script.

Change-Id: Ibbcffffcb82e0d289f0b3942728c30b8f69d28ba
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/27267
Reviewed-by: Gabe Black <gabeblack@google.com>
Maintainer: Gabe Black <gabeblack@google.com>
Tested-by: Gem5 Cloud Project GCB service account <345032938727@cloudbuild.gserviceaccount.com>
Tested-by: kokoro <noreply+kokoro@google.com>
src/mem/AbstractMemory.py
src/mem/abstract_mem.cc
src/mem/abstract_mem.hh

index 897e9e3cd5acf1c54397f43e7bdf6cd994bc4b65..4c21d529ceed6fcc0a2e64b2f2873902ed881c3b 100644 (file)
@@ -64,3 +64,8 @@ class AbstractMemory(ClockedObject):
     # configuration information about the physical memory layout to
     # the kernel, e.g. using ATAG or ACPI
     conf_table_reported = Param.Bool(True, "Report to configuration table")
+
+    # Image file to load into this memory as its initial contents. This is
+    # particularly useful for ROMs.
+    image_file = Param.String('',
+            "Image to load into memory as its initial contents")
index b5412badf41cd8221b9c49a40a17e5ae32a91d1a..aa800113bed381812f52ded27fed25fea39c1174 100644 (file)
@@ -43,6 +43,8 @@
 #include <vector>
 
 #include "arch/locked_mem.hh"
+#include "base/loader/memory_image.hh"
+#include "base/loader/object_file.hh"
 #include "cpu/base.hh"
 #include "cpu/thread_context.hh"
 #include "debug/LLSC.hh"
@@ -66,6 +68,38 @@ AbstractMemory::AbstractMemory(const Params *p) :
              range.to_string());
 }
 
+void
+AbstractMemory::initState()
+{
+    ClockedObject::initState();
+
+    const auto &file = params()->image_file;
+    if (file == "")
+        return;
+
+    auto *object = createObjectFile(file, true);
+    fatal_if(!object, "%s: Could not load %s.", name(), file);
+
+    panic_if(!object->loadGlobalSymbols(debugSymbolTable),
+             "%s: Could not load symbols from %s.", name(), file);
+
+    MemoryImage image = object->buildImage();
+
+    AddrRange image_range(image.minAddr(), image.maxAddr());
+    if (!range.contains(image_range.start())) {
+        warn("%s: Moving image from %s to memory address range %s.",
+                name(), image_range.to_string(), range.to_string());
+        image = image.offset(range.start());
+        image_range = AddrRange(image.minAddr(), image.maxAddr());
+    }
+    panic_if(!image_range.isSubset(range), "%s: memory image %s doesn't fit.",
+             name(), file);
+
+    PortProxy proxy([this](PacketPtr pkt) { functionalAccess(pkt); }, size());
+
+    panic_if(!image.write(proxy), "%s: Unable to write image.");
+}
+
 void
 AbstractMemory::setBackingStore(uint8_t* pmem_addr)
 {
index b1d54fdebe4adb39a69f6f92000ab25d645ed546..616fd0e265bac075c36860d087d4cba3e96fae40 100644 (file)
@@ -209,6 +209,8 @@ class AbstractMemory : public ClockedObject
     AbstractMemory(const Params* p);
     virtual ~AbstractMemory() {}
 
+    void initState() override;
+
     /**
      * See if this is a null memory that should never store data and
      * always return zero.