arm: Add support for automatic boot loader selection

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.
This commit is contained in:
Andreas Sandberg 2015-12-03 23:53:37 +00:00
parent 146dfd0356
commit a1aeff27ce
3 changed files with 55 additions and 12 deletions

View file

@ -1,4 +1,4 @@
# Copyright (c) 2009, 2012-2013 ARM Limited # Copyright (c) 2009, 2012-2013, 2015 ARM Limited
# All rights reserved. # All rights reserved.
# #
# The license below extends only to copyright in the software and shall # 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" cxx_header = "arch/arm/system.hh"
load_addr_mask = 0xffffffff load_addr_mask = 0xffffffff
multi_proc = Param.Bool(True, "Multiprocessor system?") 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") 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") flags_addr = Param.Addr(0, "Address of the flags register for MP booting")
have_security = Param.Bool(False, have_security = Param.Bool(False,

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2010, 2012-2013 ARM Limited * Copyright (c) 2010, 2012-2013, 2015 ARM Limited
* All rights reserved * All rights reserved
* *
* The license below extends only to copyright in the software and shall * The license below extends only to copyright in the software and shall
@ -54,7 +54,9 @@ using namespace std;
using namespace Linux; using namespace Linux;
ArmSystem::ArmSystem(Params *p) 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), _haveLPAE(p->have_lpae),
_haveVirtualization(p->have_virtualization), _haveVirtualization(p->have_virtualization),
_genericTimer(nullptr), _genericTimer(nullptr),
@ -72,12 +74,27 @@ ArmSystem::ArmSystem(Params *p)
fatal("Invalid physical address range (%d)\n", _physAddrRange64); fatal("Invalid physical address range (%d)\n", _physAddrRange64);
} }
if (p->boot_loader != "") { bootLoaders.reserve(p->boot_loader.size());
bootldr = createObjectFile(p->boot_loader); for (const auto &bl : p->boot_loader) {
std::unique_ptr<ObjectFile> obj;
obj.reset(createObjectFile(bl));
if (!bootldr) fatal_if(!obj, "Could not read bootloader: %s\n", bl);
fatal("Could not read bootloader: %s\n", p->boot_loader); 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) { if ((bootldr->getArch() == ObjectFile::Arm64) && !_highestELIs64) {
warn("Highest ARM exception-level set to AArch32 but bootloader " warn("Highest ARM exception-level set to AArch32 but bootloader "
"is for AArch64. Assuming you wanted these to match.\n"); "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"); "is for AArch32. Assuming you wanted these to match.\n");
_highestELIs64 = false; _highestELIs64 = false;
} }
bootldr->loadGlobalSymbols(debugSymbolTable);
} }
debugPrintkEvent = addKernelFuncEvent<DebugPrintkEvent>("dprintk"); debugPrintkEvent = addKernelFuncEvent<DebugPrintkEvent>("dprintk");
} }
@ -168,6 +183,17 @@ ArmSystem::~ArmSystem()
delete debugPrintkEvent; delete debugPrintkEvent;
} }
ObjectFile *
ArmSystem::getBootLoader(ObjectFile *const obj)
{
for (auto &bl : bootLoaders) {
if (bl->getArch() == obj->getArch())
return bl.get();
}
return nullptr;
}
bool bool
ArmSystem::haveLPAE(ThreadContext *tc) ArmSystem::haveLPAE(ThreadContext *tc)
{ {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2010, 2012-2013 ARM Limited * Copyright (c) 2010, 2012-2013, 2015 ARM Limited
* All rights reserved * All rights reserved
* *
* The license below extends only to copyright in the software and shall * The license below extends only to copyright in the software and shall
@ -43,6 +43,7 @@
#ifndef __ARCH_ARM_SYSTEM_HH__ #ifndef __ARCH_ARM_SYSTEM_HH__
#define __ARCH_ARM_SYSTEM_HH__ #define __ARCH_ARM_SYSTEM_HH__
#include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
@ -64,6 +65,9 @@ class ArmSystem : public System
*/ */
Linux::DebugPrintkEvent *debugPrintkEvent; Linux::DebugPrintkEvent *debugPrintkEvent;
/** Bootloaders */
std::vector<std::unique_ptr<ObjectFile>> bootLoaders;
/** /**
* Pointer to the bootloader object * Pointer to the bootloader object
*/ */
@ -112,6 +116,16 @@ class ArmSystem : public System
*/ */
const bool _haveLargeAsid64; 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: public:
typedef ArmSystemParams Params; typedef ArmSystemParams Params;
const Params * const Params *