ARM: added support for flattened device tree blobs
authorDam Sunwoo <dam.sunwoo@arm.com>
Tue, 25 Sep 2012 16:49:41 +0000 (11:49 -0500)
committerDam Sunwoo <dam.sunwoo@arm.com>
Tue, 25 Sep 2012 16:49:41 +0000 (11:49 -0500)
Newer Linux kernels require DTB (device tree blobs) to specify platform
configurations. The input DTB filename can be specified through gem5 parameters
in LinuxArmSystem.

src/arch/arm/ArmSystem.py
src/arch/arm/linux/system.cc
src/base/loader/object_file.hh

index 54bf99e9037742656633eaa41e3ab56efbdf3fe4..db0febe1823ef420c45e47497add53e48e0ad73a 100644 (file)
@@ -65,5 +65,9 @@ class LinuxArmSystem(ArmSystem):
     load_addr_mask = 0x0fffffff
     machine_type = Param.ArmMachineType('RealView_PBX',
         "Machine id from http://www.arm.linux.org.uk/developer/machines/")
-    atags_addr = Param.Addr(0x100, "Address where default atags structure should be written")
-    early_kernel_symbols = Param.Bool(False, "enable early kernel symbol tables before MMU")
+    atags_addr = Param.Addr(0x100,
+        "Address where default atags structure should be written")
+    dtb_filename = Param.String("",
+        "File that contains the Device Tree Blob. Don't use DTB if empty.")
+    early_kernel_symbols = Param.Bool(False,
+        "enable early kernel symbol tables before MMU")
index d537717ec09101c803ca9e901676430b7dc5ebd6..d9684fe66cb398fc7a73c9b55cba99bfa7eb1c49 100644 (file)
@@ -122,40 +122,73 @@ LinuxArmSystem::initState()
     }
 
     // Setup boot data structure
-    AtagCore *ac = new AtagCore;
-    ac->flags(1); // read-only
-    ac->pagesize(8192);
-    ac->rootdev(0);
-
-    AddrRangeList atagRanges = physmem.getConfAddrRanges();
-    if (atagRanges.size() != 1) {
-        fatal("Expected a single ATAG memory entry but got %d\n",
-              atagRanges.size());
+    Addr addr = 0;
+    // Check if the kernel image has a symbol that tells us it supports
+    // device trees.
+    bool kernel_has_fdt_support =
+        kernelSymtab->findAddress("unflatten_device_tree", addr);
+    bool dtb_file_specified = params()->dtb_filename != "";
+
+    if (kernel_has_fdt_support && dtb_file_specified) {
+        // Kernel supports flattened device tree and dtb file specified.
+        // Using Device Tree Blob to describe system configuration.
+        inform("Loading DTB file: %s\n", params()->dtb_filename);
+
+        ObjectFile *dtb_file = createObjectFile(params()->dtb_filename, true);
+        if (!dtb_file) {
+            fatal("couldn't load DTB file: %s\n", params()->dtb_filename);
+        }
+        dtb_file->setTextBase(params()->atags_addr);
+        dtb_file->loadSections(physProxy);
+        delete dtb_file;
+    } else {
+        // Using ATAGS
+        // Warn if the kernel supports FDT and we haven't specified one
+        if (kernel_has_fdt_support) {
+            assert(!dtb_file_specified);
+            warn("Kernel supports device tree, but no DTB file specified\n");
+        }
+        // Warn if the kernel doesn't support FDT and we have specified one
+        if (dtb_file_specified) {
+            assert(!kernel_has_fdt_support);
+            warn("DTB file specified, but no device tree support in kernel\n");
+        }
+
+        AtagCore *ac = new AtagCore;
+        ac->flags(1); // read-only
+        ac->pagesize(8192);
+        ac->rootdev(0);
+
+        AddrRangeList atagRanges = physmem.getConfAddrRanges();
+        if (atagRanges.size() != 1) {
+            fatal("Expected a single ATAG memory entry but got %d\n",
+                  atagRanges.size());
+        }
+        AtagMem *am = new AtagMem;
+        am->memSize(atagRanges.begin()->size());
+        am->memStart(atagRanges.begin()->start);
+
+        AtagCmdline *ad = new AtagCmdline;
+        ad->cmdline(params()->boot_osflags);
+
+        DPRINTF(Loader, "boot command line %d bytes: %s\n", ad->size() <<2, params()->boot_osflags.c_str());
+
+        AtagNone *an = new AtagNone;
+
+        uint32_t size = ac->size() + am->size() + ad->size() + an->size();
+        uint32_t offset = 0;
+        uint8_t *boot_data = new uint8_t[size << 2];
+
+        offset += ac->copyOut(boot_data + offset);
+        offset += am->copyOut(boot_data + offset);
+        offset += ad->copyOut(boot_data + offset);
+        offset += an->copyOut(boot_data + offset);
+
+        DPRINTF(Loader, "Boot atags was %d bytes in total\n", size << 2);
+        DDUMP(Loader, boot_data, size << 2);
+
+        physProxy.writeBlob(params()->atags_addr, boot_data, size << 2);
     }
-    AtagMem *am = new AtagMem;
-    am->memSize(atagRanges.begin()->size());
-    am->memStart(atagRanges.begin()->start);
-
-    AtagCmdline *ad = new AtagCmdline;
-    ad->cmdline(params()->boot_osflags);
-
-    DPRINTF(Loader, "boot command line %d bytes: %s\n", ad->size() <<2, params()->boot_osflags.c_str());
-
-    AtagNone *an = new AtagNone;
-
-    uint32_t size = ac->size() + am->size() + ad->size() + an->size();
-    uint32_t offset = 0;
-    uint8_t *boot_data = new uint8_t[size << 2];
-
-    offset += ac->copyOut(boot_data + offset);
-    offset += am->copyOut(boot_data + offset);
-    offset += ad->copyOut(boot_data + offset);
-    offset += an->copyOut(boot_data + offset);
-
-    DPRINTF(Loader, "Boot atags was %d bytes in total\n", size << 2);
-    DDUMP(Loader, boot_data, size << 2);
-
-    physProxy.writeBlob(params()->atags_addr, boot_data, size << 2);
 
     for (int i = 0; i < threadContexts.size(); i++) {
         threadContexts[i]->setIntReg(0, 0);
index 2ec41bf1262230034cd5e8cc6175009705482286..4a789d321b7534adc104215996be56b876e88542 100644 (file)
@@ -127,6 +127,11 @@ class ObjectFile
     size_t dataSize() const { return data.size; }
     size_t bssSize() const { return bss.size; }
 
+    /* This function allows you to override the base address where
+     * a binary is going to be loaded or set it if the binary is just a
+     * blob that doesn't include an object header.
+     * @param a address to load the binary/text section at
+     */
     void setTextBase(Addr a) { text.baseAddr = a; }
 };