arm: Add support for automatic boot loader selection
authorAndreas Sandberg <andreas.sandberg@arm.com>
Thu, 3 Dec 2015 23:53:37 +0000 (23:53 +0000)
committerAndreas Sandberg <andreas.sandberg@arm.com>
Thu, 3 Dec 2015 23:53:37 +0000 (23:53 +0000)
Add support for automatically selecting a boot loader that matches the
guest system's kernel. Instead of accepting a single boot loader, the
ArmSystem class now accepts a vector of boot loaders. When
initializing a system, the we now look for the first boot loader with
an architecture that matches the kernel.

This changeset makes it possible to use the same system for both
64-bit and 32-bit kernels.

src/arch/arm/ArmSystem.py
src/arch/arm/system.cc
src/arch/arm/system.hh

index b9769da4b02e37b9a032404f4db3a85dbac3284e..1e5acc4e658e1a427cbcd8acb507130ba0c4045d 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2009, 2012-2013 ARM Limited
+# Copyright (c) 2009, 2012-2013, 2015 ARM Limited
 # All rights reserved.
 #
 # The license below extends only to copyright in the software and shall
@@ -50,7 +50,10 @@ class ArmSystem(System):
     cxx_header = "arch/arm/system.hh"
     load_addr_mask = 0xffffffff
     multi_proc = Param.Bool(True, "Multiprocessor system?")
-    boot_loader = Param.String("", "File that contains the boot loader code if any")
+    boot_loader = VectorParam.String([],
+        "File that contains the boot loader code. Zero or more files may be "
+        "specified. The first boot loader that matches the kernel's "
+        "architecture will be used.")
     gic_cpu_addr = Param.Addr(0, "Addres of the GIC CPU interface")
     flags_addr = Param.Addr(0, "Address of the flags register for MP booting")
     have_security = Param.Bool(False,
index 8e4e825711dc530eec7521e7b5547c3fdcd6c7a0..f4241aa3ce585c66aea15d579d224f981269ff48 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2012-2013 ARM Limited
+ * Copyright (c) 2010, 2012-2013, 2015 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -54,7 +54,9 @@ using namespace std;
 using namespace Linux;
 
 ArmSystem::ArmSystem(Params *p)
-    : System(p), bootldr(NULL), _haveSecurity(p->have_security),
+    : System(p),
+      bootLoaders(), bootldr(nullptr),
+      _haveSecurity(p->have_security),
       _haveLPAE(p->have_lpae),
       _haveVirtualization(p->have_virtualization),
       _genericTimer(nullptr),
@@ -72,12 +74,27 @@ ArmSystem::ArmSystem(Params *p)
         fatal("Invalid physical address range (%d)\n", _physAddrRange64);
     }
 
-    if (p->boot_loader != "") {
-        bootldr = createObjectFile(p->boot_loader);
+    bootLoaders.reserve(p->boot_loader.size());
+    for (const auto &bl : p->boot_loader) {
+        std::unique_ptr<ObjectFile> obj;
+        obj.reset(createObjectFile(bl));
 
-        if (!bootldr)
-            fatal("Could not read bootloader: %s\n", p->boot_loader);
+        fatal_if(!obj, "Could not read bootloader: %s\n", bl);
+        bootLoaders.emplace_back(std::move(obj));
+    }
+
+    if (kernel) {
+        bootldr = getBootLoader(kernel);
+    } else if (!bootLoaders.empty()) {
+        // No kernel specified, default to the first boot loader
+        bootldr = bootLoaders[0].get();
+    }
+
+    if (!bootLoaders.empty() && !bootldr)
+        fatal("Can't find a matching boot loader / kernel combination!");
 
+    if (bootldr) {
+        bootldr->loadGlobalSymbols(debugSymbolTable);
         if ((bootldr->getArch() == ObjectFile::Arm64) && !_highestELIs64) {
             warn("Highest ARM exception-level set to AArch32 but bootloader "
                   "is for AArch64. Assuming you wanted these to match.\n");
@@ -87,10 +104,8 @@ ArmSystem::ArmSystem(Params *p)
                   "is for AArch32. Assuming you wanted these to match.\n");
             _highestELIs64 = false;
         }
-
-        bootldr->loadGlobalSymbols(debugSymbolTable);
-
     }
+
     debugPrintkEvent = addKernelFuncEvent<DebugPrintkEvent>("dprintk");
 }
 
@@ -168,6 +183,17 @@ ArmSystem::~ArmSystem()
         delete debugPrintkEvent;
 }
 
+ObjectFile *
+ArmSystem::getBootLoader(ObjectFile *const obj)
+{
+    for (auto &bl : bootLoaders) {
+        if (bl->getArch() == obj->getArch())
+            return bl.get();
+    }
+
+    return nullptr;
+}
+
 bool
 ArmSystem::haveLPAE(ThreadContext *tc)
 {
index 0b652f76cbc464e5260aaa1e34704b8576ecfef8..511118d4dcb9b313583e4abe593f0a31aa863157 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2012-2013 ARM Limited
+ * Copyright (c) 2010, 2012-2013, 2015 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -43,6 +43,7 @@
 #ifndef __ARCH_ARM_SYSTEM_HH__
 #define __ARCH_ARM_SYSTEM_HH__
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -64,6 +65,9 @@ class ArmSystem : public System
      */
     Linux::DebugPrintkEvent *debugPrintkEvent;
 
+    /** Bootloaders */
+    std::vector<std::unique_ptr<ObjectFile>> bootLoaders;
+
     /**
      * Pointer to the bootloader object
      */
@@ -112,6 +116,16 @@ class ArmSystem : public System
      */
     const bool _haveLargeAsid64;
 
+  protected:
+    /**
+     * Get a boot loader that matches the kernel.
+     *
+     * @param obj Kernel binary
+     * @return Pointer to boot loader ObjectFile or nullptr if there
+     *         is no matching boot loader.
+     */
+    ObjectFile *getBootLoader(ObjectFile *const obj);
+
   public:
     typedef ArmSystemParams Params;
     const Params *