loader: add a flattened device tree blob (dtb) object
authorAnthony Gutierrez <atgutier@umich.edu>
Fri, 15 Feb 2013 23:48:59 +0000 (18:48 -0500)
committerAnthony Gutierrez <atgutier@umich.edu>
Fri, 15 Feb 2013 23:48:59 +0000 (18:48 -0500)
this adds a dtb_object so the loader can load in the dtb
file for linux/android ARM kernels.

src/arch/arm/linux/system.cc
src/base/SConscript
src/base/loader/dtb_object.cc [new file with mode: 0644]
src/base/loader/dtb_object.hh [new file with mode: 0644]
src/base/loader/object_file.cc

index 74950cbafce9b4da70c01063f49ab67ad7f1072e..4478aadf40cf473ec1910a64902531015d0a13b8 100644 (file)
@@ -45,6 +45,7 @@
 #include "arch/arm/isa_traits.hh"
 #include "arch/arm/utility.hh"
 #include "arch/generic/linux/threadinfo.hh"
+#include "base/loader/dtb_object.hh"
 #include "base/loader/object_file.hh"
 #include "base/loader/symtab.hh"
 #include "cpu/base.hh"
@@ -143,6 +144,20 @@ LinuxArmSystem::initState()
         if (!dtb_file) {
             fatal("couldn't load DTB file: %s\n", params()->dtb_filename);
         }
+
+        DtbObject *_dtb_file = dynamic_cast<DtbObject*>(dtb_file);
+
+        if (_dtb_file) {
+            if (!_dtb_file->addBootCmdLine(params()->boot_osflags.c_str(),
+                                           params()->boot_osflags.size())) {
+                warn("couldn't append bootargs to DTB file: %s\n",
+                     params()->dtb_filename);
+            }
+        } else {
+            warn("dtb_file cast failed; couldn't append bootargs "
+                 "to DTB file: %s\n", params()->dtb_filename);
+        }
+
         dtb_file->setTextBase(params()->atags_addr);
         dtb_file->loadSections(physProxy);
         delete dtb_file;
index 2bd255162512188c9d85f627889f877245d72271..b2a348f1544a2a8081f91cc5eb722af679656163 100644 (file)
@@ -63,6 +63,7 @@ Source('types.cc')
 Source('userinfo.cc')
 
 Source('loader/aout_object.cc')
+Source('loader/dtb_object.cc')
 Source('loader/ecoff_object.cc')
 Source('loader/elf_object.cc')
 Source('loader/hex_file.cc')
diff --git a/src/base/loader/dtb_object.cc b/src/base/loader/dtb_object.cc
new file mode 100644 (file)
index 0000000..f22cee1
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2013 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Anthony Gutierrez
+ */
+
+#include <sys/mman.h>
+#include <err.h>
+#include <unistd.h>
+
+#include <cassert>
+
+#include "base/loader/dtb_object.hh"
+#include "fdt.h"
+#include "libfdt.h"
+
+ObjectFile *
+DtbObject::tryFile(const std::string &fname, int fd, size_t len, uint8_t *data)
+{
+    // Check if this is a FDT file by looking for magic number
+    if (fdt_magic((void*)data) == FDT_MAGIC) {
+        return new DtbObject(fname, fd, len, data,
+                             ObjectFile::UnknownArch, ObjectFile::UnknownOpSys);
+    } else {
+        return NULL;
+    }
+}
+
+DtbObject::DtbObject(const std::string &_filename, int _fd,
+                     size_t _len, uint8_t *_data,
+                     Arch _arch, OpSys _opSys)
+    : ObjectFile(_filename, _fd, _len, _data, _arch, _opSys)
+{
+    text.baseAddr = 0;
+    text.size = len;
+    text.fileImage = fileData;
+
+    data.baseAddr = 0;
+    data.size = 0;
+    data.fileImage = NULL;
+
+    bss.baseAddr = 0;
+    bss.size = 0;
+    bss.fileImage = NULL;
+
+    fileDataMmapped = true;
+}
+
+DtbObject::~DtbObject()
+{
+    if (descriptor >= 0) {
+        ::close(descriptor);
+        descriptor = -1;
+    }
+
+    // Make sure to clean up memory properly depending
+    // on how buffer was allocated.
+    if (fileData && !fileDataMmapped) {
+        delete [] fileData;
+        fileData = NULL;
+    } else if (fileData) {
+        munmap(fileData, len);
+        fileData = NULL;
+    }
+}
+
+bool
+DtbObject::addBootCmdLine(const char* _args, size_t len)
+{
+    const char* root_path = "/";
+    const char* node_name = "chosen";
+    const char* full_path_node_name = "/chosen";
+    const char* property_name = "bootargs";
+
+    // Make a new buffer that has extra space to add nodes/properties
+    int newLen = 2*this->len;
+    uint8_t* fdt_buf_w_space = new uint8_t[newLen];
+    // Copy and unpack flattened device tree into new buffer
+    int ret = fdt_open_into((void*)fileData, (void*)fdt_buf_w_space, (newLen));
+    if (ret < 0) {
+        warn("Error resizing buffer of flattened device tree, "
+             "errno: %d\n", ret);
+        delete [] fdt_buf_w_space;
+        return false;
+    }
+
+    // First try finding the /chosen node in the dtb
+    int offset = fdt_path_offset((void*)fdt_buf_w_space, full_path_node_name);
+    if (offset < 0) {
+        // try adding the node by walking dtb tree to proper insertion point
+        offset = fdt_path_offset((void*)fdt_buf_w_space, root_path);
+        offset = fdt_add_subnode((void*)fdt_buf_w_space, offset, node_name);
+        offset = fdt_path_offset((void*)fdt_buf_w_space, full_path_node_name);
+        if (offset < 0) {
+            warn("Error finding or adding \"chosen\" subnode to flattened "
+                 "device tree, errno: %d\n", offset);
+            delete [] fdt_buf_w_space;
+            return false;
+        }
+    }
+
+    // Set the bootargs property in the /chosen node
+    ret = fdt_setprop((void*)fdt_buf_w_space, offset, property_name,
+                      (const void*)_args, len+1);
+    if (ret < 0) {
+        warn("Error setting \"bootargs\" property to flattened device tree, "
+             "errno: %d\n", ret);
+        delete [] fdt_buf_w_space;
+        return false;
+    }
+
+    // Repack the dtb for kernel use
+    ret = fdt_pack((void*)fdt_buf_w_space);
+    if (ret < 0) {
+        warn("Error re-packing flattened device tree structure, "
+             "errno: %d\n", ret);
+        delete [] fdt_buf_w_space;
+        return false;
+    }
+
+    text.size = newLen;
+    text.fileImage = fdt_buf_w_space;
+
+    // clean up old buffer and set to new fdt blob
+    munmap(fileData, this->len);
+    fileData = fdt_buf_w_space;
+    fileDataMmapped = false;
+    this->len = newLen;
+
+    return true;
+}
+
+bool
+DtbObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask)
+{
+    // nothing to do here
+    return false;
+}
+
+bool
+DtbObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask)
+{
+    // nothing to do here
+    return false;
+}
diff --git a/src/base/loader/dtb_object.hh b/src/base/loader/dtb_object.hh
new file mode 100644 (file)
index 0000000..ec52945
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2013 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Anthony Gutierrez
+ */
+
+#ifndef __DTB_OBJECT_HH__
+#define __DTB_OBJECT_HH__
+
+#include "base/loader/object_file.hh"
+
+/** @file
+ * This implements an object file format to support loading
+ * and modifying flattened device tree blobs for use with
+ * current and future ARM Linux kernels.
+ */
+class DtbObject : public ObjectFile
+{
+    protected:
+        DtbObject(const std::string &_filename, int _fd,
+                  size_t _len, uint8_t *_data,
+                  Arch _arch, OpSys _opSys);
+
+        /** Bool marking if this dtb file has replaced the original
+         *  read in DTB file with a new modified buffer
+         */
+        bool fileDataMmapped;
+
+    public:
+        virtual ~DtbObject();
+
+        /** Adds the passed in Command Line options for the kernel
+          * to the proper location in the device tree.
+          * @param _args command line to append
+          * @param len length of the command line string
+          * @return returns true on success, false otherwise
+          */
+        bool addBootCmdLine(const char* _args, size_t len);
+        bool loadGlobalSymbols(SymbolTable *symtab,
+            Addr addrMask = std::numeric_limits<Addr>::max());
+        bool loadLocalSymbols(SymbolTable *symtab,
+            Addr addrMask = std::numeric_limits<Addr>::max());
+
+        /** Static function that tries to load file as a
+          * flattened device tree blob.
+          * @param fname path to file
+          * @param fd file descriptor of object file
+          * @param len length of file
+          * @param data mmap'ed data buffer containing file contents
+          * @return ObjectFile representing closest match of file type
+          */
+        static ObjectFile *tryFile(const std::string &fname, int fd,
+                                   size_t len, uint8_t *data);
+};
+
+#endif //__DTB_OBJECT_HH__
index 80fc9c2f949a993b1071401037bb7f7afef229b5..b9f84283bd5eb8926445fc92d411d40fa84581e0 100644 (file)
@@ -39,6 +39,7 @@
 #include <string>
 
 #include "base/loader/aout_object.hh"
+#include "base/loader/dtb_object.hh"
 #include "base/loader/ecoff_object.hh"
 #include "base/loader/elf_object.hh"
 #include "base/loader/object_file.hh"
@@ -140,6 +141,10 @@ createObjectFile(const string &fname, bool raw)
         return fileObj;
     }
 
+    if ((fileObj = DtbObject::tryFile(fname, fd, len, fileData)) != NULL) {
+        return fileObj;
+    }
+
     if (raw)
         return RawObject::tryFile(fname, fd, len, fileData);