summaryrefslogtreecommitdiff
path: root/src/arch/arm/system.cc
diff options
context:
space:
mode:
authorARM gem5 Developers <none@none>2014-01-24 15:29:34 -0600
committerARM gem5 Developers <none@none>2014-01-24 15:29:34 -0600
commit612f8f074fa1099cf70faf495d46cc647762a031 (patch)
treebd1e99c43bf15292395eadd4b7ae3f5c823545c3 /src/arch/arm/system.cc
parentf3585c841e964c98911784a187fc4f081a02a0a6 (diff)
downloadgem5-612f8f074fa1099cf70faf495d46cc647762a031.tar.xz
arm: Add support for ARMv8 (AArch64 & AArch32)
Note: AArch64 and AArch32 interworking is not supported. If you use an AArch64 kernel you are restricted to AArch64 user-mode binaries. This will be addressed in a later patch. Note: Virtualization is only supported in AArch32 mode. This will also be fixed in a later patch. Contributors: Giacomo Gabrielli (TrustZone, LPAE, system-level AArch64, AArch64 NEON, validation) Thomas Grocutt (AArch32 Virtualization, AArch64 FP, validation) Mbou Eyole (AArch64 NEON, validation) Ali Saidi (AArch64 Linux support, code integration, validation) Edmund Grimley-Evans (AArch64 FP) William Wang (AArch64 Linux support) Rene De Jong (AArch64 Linux support, performance opt.) Matt Horsnell (AArch64 MP, validation) Matt Evans (device models, code integration, validation) Chris Adeniyi-Jones (AArch64 syscall-emulation) Prakash Ramrakhyani (validation) Dam Sunwoo (validation) Chander Sudanthi (validation) Stephan Diestelhorst (validation) Andreas Hansson (code integration, performance opt.) Eric Van Hensbergen (performance opt.) Gabe Black
Diffstat (limited to 'src/arch/arm/system.cc')
-rw-r--r--src/arch/arm/system.cc143
1 files changed, 136 insertions, 7 deletions
diff --git a/src/arch/arm/system.cc b/src/arch/arm/system.cc
index b09784b64..00d9d7613 100644
--- a/src/arch/arm/system.cc
+++ b/src/arch/arm/system.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010, 2012-2013 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@@ -48,19 +48,46 @@
#include "cpu/thread_context.hh"
#include "mem/physical.hh"
#include "mem/fs_translating_port_proxy.hh"
+#include "sim/full_system.hh"
using namespace std;
using namespace Linux;
ArmSystem::ArmSystem(Params *p)
- : System(p), bootldr(NULL), multiProc(p->multi_proc)
+ : System(p), bootldr(NULL), _haveSecurity(p->have_security),
+ _haveLPAE(p->have_lpae),
+ _haveVirtualization(p->have_virtualization),
+ _haveGenericTimer(p->have_generic_timer),
+ _highestELIs64(p->highest_el_is_64),
+ _resetAddr64(p->reset_addr_64),
+ _physAddrRange64(p->phys_addr_range_64),
+ _haveLargeAsid64(p->have_large_asid_64),
+ multiProc(p->multi_proc)
{
+ // Check if the physical address range is valid
+ if (_highestELIs64 && (
+ _physAddrRange64 < 32 ||
+ _physAddrRange64 > 48 ||
+ (_physAddrRange64 % 4 != 0 && _physAddrRange64 != 42))) {
+ fatal("Invalid physical address range (%d)\n", _physAddrRange64);
+ }
+
if (p->boot_loader != "") {
bootldr = createObjectFile(p->boot_loader);
if (!bootldr)
fatal("Could not read bootloader: %s\n", p->boot_loader);
+ 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");
+ _highestELIs64 = true;
+ } else if ((bootldr->getArch() == ObjectFile::Arm) && _highestELIs64) {
+ warn("Highest ARM exception-level set to AArch64 but bootloader "
+ "is for AArch32. Assuming you wanted these to match.\n");
+ _highestELIs64 = false;
+ }
+
bootldr->loadGlobalSymbols(debugSymbolTable);
}
@@ -81,11 +108,21 @@ ArmSystem::initState()
if (bootldr) {
bootldr->loadSections(physProxy);
- uint8_t jump_to_bl[] =
+ uint8_t jump_to_bl_32[] =
+ {
+ 0x07, 0xf0, 0xa0, 0xe1 // branch to r7 in aarch32
+ };
+
+ uint8_t jump_to_bl_64[] =
{
- 0x07, 0xf0, 0xa0, 0xe1 // branch to r7
+ 0xe0, 0x00, 0x1f, 0xd6 // instruction "br x7" in aarch64
};
- physProxy.writeBlob(0x0, jump_to_bl, sizeof(jump_to_bl));
+
+ // write the jump to branch table into address 0
+ if (!_highestELIs64)
+ physProxy.writeBlob(0x0, jump_to_bl_32, sizeof(jump_to_bl_32));
+ else
+ physProxy.writeBlob(0x0, jump_to_bl_64, sizeof(jump_to_bl_64));
inform("Using bootloader at address %#x\n", bootldr->entryPoint());
@@ -96,24 +133,116 @@ ArmSystem::initState()
fatal("gic_cpu_addr && flags_addr must be set with bootloader\n");
for (int i = 0; i < threadContexts.size(); i++) {
- threadContexts[i]->setIntReg(3, kernelEntry & loadAddrMask);
+ if (!_highestELIs64)
+ threadContexts[i]->setIntReg(3, (kernelEntry & loadAddrMask) +
+ loadAddrOffset);
threadContexts[i]->setIntReg(4, params()->gic_cpu_addr);
threadContexts[i]->setIntReg(5, params()->flags_addr);
threadContexts[i]->setIntReg(7, bootldr->entryPoint());
}
+ inform("Using kernel entry physical address at %#x\n",
+ (kernelEntry & loadAddrMask) + loadAddrOffset);
} else {
// Set the initial PC to be at start of the kernel code
- threadContexts[0]->pcState(kernelEntry & loadAddrMask);
+ if (!_highestELIs64)
+ threadContexts[0]->pcState((kernelEntry & loadAddrMask) +
+ loadAddrOffset);
+ }
+}
+
+GenericTimer::ArchTimer *
+ArmSystem::getArchTimer(int cpu_id) const
+{
+ if (_genericTimer) {
+ return _genericTimer->getArchTimer(cpu_id);
}
+ return NULL;
}
+GenericTimer::SystemCounter *
+ArmSystem::getSystemCounter() const
+{
+ if (_genericTimer) {
+ return _genericTimer->getSystemCounter();
+ }
+ return NULL;
+}
+
+bool
+ArmSystem::haveSecurity(ThreadContext *tc)
+{
+ if (!FullSystem)
+ return false;
+
+ ArmSystem *a_sys = dynamic_cast<ArmSystem *>(tc->getSystemPtr());
+ assert(a_sys);
+ return a_sys->haveSecurity();
+}
+
+
ArmSystem::~ArmSystem()
{
if (debugPrintkEvent)
delete debugPrintkEvent;
}
+bool
+ArmSystem::haveLPAE(ThreadContext *tc)
+{
+ if (!FullSystem)
+ return false;
+ ArmSystem *a_sys = dynamic_cast<ArmSystem *>(tc->getSystemPtr());
+ assert(a_sys);
+ return a_sys->haveLPAE();
+}
+
+bool
+ArmSystem::haveVirtualization(ThreadContext *tc)
+{
+ if (!FullSystem)
+ return false;
+
+ ArmSystem *a_sys = dynamic_cast<ArmSystem *>(tc->getSystemPtr());
+ assert(a_sys);
+ return a_sys->haveVirtualization();
+}
+
+bool
+ArmSystem::highestELIs64(ThreadContext *tc)
+{
+ return dynamic_cast<ArmSystem *>(tc->getSystemPtr())->highestELIs64();
+}
+
+ExceptionLevel
+ArmSystem::highestEL(ThreadContext *tc)
+{
+ return dynamic_cast<ArmSystem *>(tc->getSystemPtr())->highestEL();
+}
+
+Addr
+ArmSystem::resetAddr64(ThreadContext *tc)
+{
+ return dynamic_cast<ArmSystem *>(tc->getSystemPtr())->resetAddr64();
+}
+
+uint8_t
+ArmSystem::physAddrRange(ThreadContext *tc)
+{
+ return dynamic_cast<ArmSystem *>(tc->getSystemPtr())->physAddrRange();
+}
+
+Addr
+ArmSystem::physAddrMask(ThreadContext *tc)
+{
+ return dynamic_cast<ArmSystem *>(tc->getSystemPtr())->physAddrMask();
+}
+
+bool
+ArmSystem::haveLargeAsid64(ThreadContext *tc)
+{
+ return dynamic_cast<ArmSystem *>(tc->getSystemPtr())->haveLargeAsid64();
+}
ArmSystem *
ArmSystemParams::create()
{