system.cc revision 12318:1402d90f344f
112070Snikos.nikoleris@arm.com/*
29380SAndreas.Sandberg@ARM.com * Copyright (c) 2010, 2012-2013, 2015,2017 ARM Limited
39380SAndreas.Sandberg@ARM.com * All rights reserved
49380SAndreas.Sandberg@ARM.com *
59380SAndreas.Sandberg@ARM.com * The license below extends only to copyright in the software and shall
69380SAndreas.Sandberg@ARM.com * not be construed as granting a license to any other intellectual
79380SAndreas.Sandberg@ARM.com * property including but not limited to intellectual property relating
89380SAndreas.Sandberg@ARM.com * to a hardware implementation of the functionality of the software
99380SAndreas.Sandberg@ARM.com * licensed hereunder.  You may use the software subject to the license
109380SAndreas.Sandberg@ARM.com * terms below provided that you ensure that this notice is replicated
119380SAndreas.Sandberg@ARM.com * unmodified and in its entirety in all distributions of the software,
129380SAndreas.Sandberg@ARM.com * modified or unmodified, in source code or in binary form.
139380SAndreas.Sandberg@ARM.com *
149380SAndreas.Sandberg@ARM.com * Copyright (c) 2002-2006 The Regents of The University of Michigan
159380SAndreas.Sandberg@ARM.com * All rights reserved.
169380SAndreas.Sandberg@ARM.com *
179380SAndreas.Sandberg@ARM.com * Redistribution and use in source and binary forms, with or without
189380SAndreas.Sandberg@ARM.com * modification, are permitted provided that the following conditions are
199380SAndreas.Sandberg@ARM.com * met: redistributions of source code must retain the above copyright
209380SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer;
219380SAndreas.Sandberg@ARM.com * redistributions in binary form must reproduce the above copyright
229380SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer in the
239380SAndreas.Sandberg@ARM.com * documentation and/or other materials provided with the distribution;
249380SAndreas.Sandberg@ARM.com * neither the name of the copyright holders nor the names of its
259380SAndreas.Sandberg@ARM.com * contributors may be used to endorse or promote products derived from
269380SAndreas.Sandberg@ARM.com * this software without specific prior written permission.
279380SAndreas.Sandberg@ARM.com *
289380SAndreas.Sandberg@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
299380SAndreas.Sandberg@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
309380SAndreas.Sandberg@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
319380SAndreas.Sandberg@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
329380SAndreas.Sandberg@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
339380SAndreas.Sandberg@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
349380SAndreas.Sandberg@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
359380SAndreas.Sandberg@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
369380SAndreas.Sandberg@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
379792Sandreas.hansson@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
389380SAndreas.Sandberg@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
399380SAndreas.Sandberg@ARM.com *
4012070Snikos.nikoleris@arm.com * Authors: Ali Saidi
419380SAndreas.Sandberg@ARM.com */
429380SAndreas.Sandberg@ARM.com
439380SAndreas.Sandberg@ARM.com#include "arch/arm/system.hh"
4411682Sandreas.hansson@arm.com
4511682Sandreas.hansson@arm.com#include <iostream>
4612070Snikos.nikoleris@arm.com
4711682Sandreas.hansson@arm.com#include "base/loader/object_file.hh"
4812070Snikos.nikoleris@arm.com#include "base/loader/symtab.hh"
499380SAndreas.Sandberg@ARM.com#include "cpu/thread_context.hh"
509654SAndreas.Sandberg@ARM.com#include "mem/fs_translating_port_proxy.hh"
519654SAndreas.Sandberg@ARM.com#include "mem/physical.hh"
529380SAndreas.Sandberg@ARM.com#include "sim/full_system.hh"
539380SAndreas.Sandberg@ARM.com
549380SAndreas.Sandberg@ARM.comusing namespace std;
559380SAndreas.Sandberg@ARM.comusing namespace Linux;
569380SAndreas.Sandberg@ARM.com
579380SAndreas.Sandberg@ARM.comArmSystem::ArmSystem(Params *p)
589380SAndreas.Sandberg@ARM.com    : System(p),
599380SAndreas.Sandberg@ARM.com      bootLoaders(), bootldr(nullptr),
609380SAndreas.Sandberg@ARM.com      _haveSecurity(p->have_security),
619380SAndreas.Sandberg@ARM.com      _haveLPAE(p->have_lpae),
629380SAndreas.Sandberg@ARM.com      _haveVirtualization(p->have_virtualization),
639792Sandreas.hansson@arm.com      _genericTimer(nullptr),
6411156Sandreas.sandberg@arm.com      _highestELIs64(p->highest_el_is_64),
6512070Snikos.nikoleris@arm.com      _resetAddr64(p->reset_addr_64),
669792Sandreas.hansson@arm.com      _physAddrRange64(p->phys_addr_range_64),
679380SAndreas.Sandberg@ARM.com      _haveLargeAsid64(p->have_large_asid_64),
689380SAndreas.Sandberg@ARM.com      _m5opRange(p->m5ops_base ?
699380SAndreas.Sandberg@ARM.com                 RangeSize(p->m5ops_base, 0x10000) :
709792Sandreas.hansson@arm.com                 AddrRange(1, 0)), // Create an empty range if disabled
719380SAndreas.Sandberg@ARM.com      multiProc(p->multi_proc)
729380SAndreas.Sandberg@ARM.com{
739380SAndreas.Sandberg@ARM.com    // Check if the physical address range is valid
7410512SAli.Saidi@ARM.com    if (_highestELIs64 && (
7512070Snikos.nikoleris@arm.com            _physAddrRange64 < 32 ||
769380SAndreas.Sandberg@ARM.com            _physAddrRange64 > 48 ||
779380SAndreas.Sandberg@ARM.com            (_physAddrRange64 % 4 != 0 && _physAddrRange64 != 42))) {
789792Sandreas.hansson@arm.com        fatal("Invalid physical address range (%d)\n", _physAddrRange64);
799380SAndreas.Sandberg@ARM.com    }
809380SAndreas.Sandberg@ARM.com
8111156Sandreas.sandberg@arm.com    bootLoaders.reserve(p->boot_loader.size());
829380SAndreas.Sandberg@ARM.com    for (const auto &bl : p->boot_loader) {
8312070Snikos.nikoleris@arm.com        std::unique_ptr<ObjectFile> obj;
849380SAndreas.Sandberg@ARM.com        obj.reset(createObjectFile(bl));
859793Sakash.bagdia@arm.com
869380SAndreas.Sandberg@ARM.com        fatal_if(!obj, "Could not read bootloader: %s\n", bl);
8711156Sandreas.sandberg@arm.com        bootLoaders.emplace_back(std::move(obj));
8811156Sandreas.sandberg@arm.com    }
899793Sakash.bagdia@arm.com
909380SAndreas.Sandberg@ARM.com    if (kernel) {
919380SAndreas.Sandberg@ARM.com        bootldr = getBootLoader(kernel);
929380SAndreas.Sandberg@ARM.com    } else if (!bootLoaders.empty()) {
939380SAndreas.Sandberg@ARM.com        // No kernel specified, default to the first boot loader
949380SAndreas.Sandberg@ARM.com        bootldr = bootLoaders[0].get();
959380SAndreas.Sandberg@ARM.com    }
969380SAndreas.Sandberg@ARM.com
979380SAndreas.Sandberg@ARM.com    if (!bootLoaders.empty() && !bootldr)
989380SAndreas.Sandberg@ARM.com        fatal("Can't find a matching boot loader / kernel combination!");
999380SAndreas.Sandberg@ARM.com
1009380SAndreas.Sandberg@ARM.com    if (bootldr) {
1019380SAndreas.Sandberg@ARM.com        bootldr->loadGlobalSymbols(debugSymbolTable);
10210884Sandreas.hansson@arm.com        if ((bootldr->getArch() == ObjectFile::Arm64) && !_highestELIs64) {
10310884Sandreas.hansson@arm.com            warn("Highest ARM exception-level set to AArch32 but bootloader "
1049380SAndreas.Sandberg@ARM.com                  "is for AArch64. Assuming you wanted these to match.\n");
1059380SAndreas.Sandberg@ARM.com            _highestELIs64 = true;
1069380SAndreas.Sandberg@ARM.com        } else if ((bootldr->getArch() == ObjectFile::Arm) && _highestELIs64) {
1079380SAndreas.Sandberg@ARM.com            warn("Highest ARM exception-level set to AArch64 but bootloader "
1089380SAndreas.Sandberg@ARM.com                  "is for AArch32. Assuming you wanted these to match.\n");
1099380SAndreas.Sandberg@ARM.com            _highestELIs64 = false;
1109380SAndreas.Sandberg@ARM.com        }
1119380SAndreas.Sandberg@ARM.com    }
1129380SAndreas.Sandberg@ARM.com
1139380SAndreas.Sandberg@ARM.com    debugPrintkEvent = addKernelFuncEvent<DebugPrintkEvent>("dprintk");
11410720Sandreas.hansson@arm.com}
1159793Sakash.bagdia@arm.com
1169793Sakash.bagdia@arm.comvoid
1179380SAndreas.Sandberg@ARM.comArmSystem::initState()
1189380SAndreas.Sandberg@ARM.com{
1199380SAndreas.Sandberg@ARM.com    // Moved from the constructor to here since it relies on the
1209380SAndreas.Sandberg@ARM.com    // address map being resolved in the interconnect
1219674Snilay@cs.wisc.edu
1229380SAndreas.Sandberg@ARM.com    // Call the initialisation of the super class
1239380SAndreas.Sandberg@ARM.com    System::initState();
1249380SAndreas.Sandberg@ARM.com
1259380SAndreas.Sandberg@ARM.com    const Params* p = params();
1269380SAndreas.Sandberg@ARM.com
1279380SAndreas.Sandberg@ARM.com    if (bootldr) {
1289674Snilay@cs.wisc.edu        bootldr->loadSections(physProxy);
1299674Snilay@cs.wisc.edu
1309674Snilay@cs.wisc.edu        uint8_t jump_to_bl_32[] =
1319674Snilay@cs.wisc.edu        {
1329674Snilay@cs.wisc.edu            0x07, 0xf0, 0xa0, 0xe1  // branch to r7 in aarch32
1339380SAndreas.Sandberg@ARM.com        };
1349654SAndreas.Sandberg@ARM.com
1359654SAndreas.Sandberg@ARM.com        uint8_t jump_to_bl_64[] =
1369654SAndreas.Sandberg@ARM.com        {
1379654SAndreas.Sandberg@ARM.com            0xe0, 0x00, 0x1f, 0xd6  // instruction "br x7" in aarch64
1389654SAndreas.Sandberg@ARM.com        };
1399654SAndreas.Sandberg@ARM.com
1409654SAndreas.Sandberg@ARM.com        // write the jump to branch table into address 0
1419654SAndreas.Sandberg@ARM.com        if (!_highestELIs64)
1429380SAndreas.Sandberg@ARM.com            physProxy.writeBlob(0x0, jump_to_bl_32, sizeof(jump_to_bl_32));
1439380SAndreas.Sandberg@ARM.com        else
1449380SAndreas.Sandberg@ARM.com            physProxy.writeBlob(0x0, jump_to_bl_64, sizeof(jump_to_bl_64));
1459380SAndreas.Sandberg@ARM.com
1469380SAndreas.Sandberg@ARM.com        inform("Using bootloader at address %#x\n", bootldr->entryPoint());
1479380SAndreas.Sandberg@ARM.com
1489793Sakash.bagdia@arm.com        // Put the address of the boot loader into r7 so we know
1499793Sakash.bagdia@arm.com        // where to branch to after the reset fault
1509380SAndreas.Sandberg@ARM.com        // All other values needed by the boot loader to know what to do
1519654SAndreas.Sandberg@ARM.com        if (!p->gic_cpu_addr || !p->flags_addr)
1529654SAndreas.Sandberg@ARM.com            fatal("gic_cpu_addr && flags_addr must be set with bootloader\n");
1539654SAndreas.Sandberg@ARM.com
1549654SAndreas.Sandberg@ARM.com        for (int i = 0; i < threadContexts.size(); i++) {
15512070Snikos.nikoleris@arm.com            if (!_highestELIs64)
15612070Snikos.nikoleris@arm.com                threadContexts[i]->setIntReg(3, (kernelEntry & loadAddrMask) +
15712070Snikos.nikoleris@arm.com                        loadAddrOffset);
15812070Snikos.nikoleris@arm.com            threadContexts[i]->setIntReg(4, params()->gic_cpu_addr);
15912070Snikos.nikoleris@arm.com            threadContexts[i]->setIntReg(5, params()->flags_addr);
16012070Snikos.nikoleris@arm.com            threadContexts[i]->setIntReg(7, bootldr->entryPoint());
16111604Sandreas.hansson@arm.com        }
16212070Snikos.nikoleris@arm.com        inform("Using kernel entry physical address at %#x\n",
16312070Snikos.nikoleris@arm.com               (kernelEntry & loadAddrMask) + loadAddrOffset);
16412070Snikos.nikoleris@arm.com    } else {
16512070Snikos.nikoleris@arm.com        // Set the initial PC to be at start of the kernel code
16612070Snikos.nikoleris@arm.com        if (!_highestELIs64)
16712070Snikos.nikoleris@arm.com            threadContexts[0]->pcState((kernelEntry & loadAddrMask) +
16812070Snikos.nikoleris@arm.com                    loadAddrOffset);
16912070Snikos.nikoleris@arm.com    }
17012070Snikos.nikoleris@arm.com}
17112070Snikos.nikoleris@arm.com
17212070Snikos.nikoleris@arm.comArmSystem*
17312598Snikos.nikoleris@arm.comArmSystem::getArmSystem(ThreadContext *tc)
17412070Snikos.nikoleris@arm.com{
17512598Snikos.nikoleris@arm.com    ArmSystem *a_sys = dynamic_cast<ArmSystem *>(tc->getSystemPtr());
17612070Snikos.nikoleris@arm.com    assert(a_sys);
17712070Snikos.nikoleris@arm.com    return a_sys;
17812070Snikos.nikoleris@arm.com}
17912070Snikos.nikoleris@arm.com
18012070Snikos.nikoleris@arm.combool
18112070Snikos.nikoleris@arm.comArmSystem::haveSecurity(ThreadContext *tc)
18212070Snikos.nikoleris@arm.com{
18312070Snikos.nikoleris@arm.com    return FullSystem? getArmSystem(tc)->haveSecurity() : false;
18412070Snikos.nikoleris@arm.com}
18512070Snikos.nikoleris@arm.com
18612070Snikos.nikoleris@arm.com
18712070Snikos.nikoleris@arm.comArmSystem::~ArmSystem()
18812070Snikos.nikoleris@arm.com{
18912070Snikos.nikoleris@arm.com    if (debugPrintkEvent)
1909380SAndreas.Sandberg@ARM.com        delete debugPrintkEvent;
1919793Sakash.bagdia@arm.com}
1929793Sakash.bagdia@arm.com
1939793Sakash.bagdia@arm.comObjectFile *
1949793Sakash.bagdia@arm.comArmSystem::getBootLoader(ObjectFile *const obj)
1959827Sakash.bagdia@arm.com{
1969827Sakash.bagdia@arm.com    for (auto &bl : bootLoaders) {
1979827Sakash.bagdia@arm.com        if (bl->getArch() == obj->getArch())
1989827Sakash.bagdia@arm.com            return bl.get();
1999793Sakash.bagdia@arm.com    }
2009793Sakash.bagdia@arm.com
2019793Sakash.bagdia@arm.com    return nullptr;
2029827Sakash.bagdia@arm.com}
2039827Sakash.bagdia@arm.com
2049827Sakash.bagdia@arm.combool
2059793Sakash.bagdia@arm.comArmSystem::haveLPAE(ThreadContext *tc)
2069380SAndreas.Sandberg@ARM.com{
2079380SAndreas.Sandberg@ARM.com    return FullSystem? getArmSystem(tc)->haveLPAE() : false;
2089380SAndreas.Sandberg@ARM.com}
2099380SAndreas.Sandberg@ARM.com
2109380SAndreas.Sandberg@ARM.combool
2119380SAndreas.Sandberg@ARM.comArmSystem::haveVirtualization(ThreadContext *tc)
2129380SAndreas.Sandberg@ARM.com{
2139380SAndreas.Sandberg@ARM.com    return FullSystem? getArmSystem(tc)->haveVirtualization() : false;
2149380SAndreas.Sandberg@ARM.com}
2159380SAndreas.Sandberg@ARM.com
2169380SAndreas.Sandberg@ARM.combool
2179792Sandreas.hansson@arm.comArmSystem::highestELIs64(ThreadContext *tc)
2189792Sandreas.hansson@arm.com{
2199792Sandreas.hansson@arm.com    return FullSystem? getArmSystem(tc)->highestELIs64() : true;
2209792Sandreas.hansson@arm.com}
2219792Sandreas.hansson@arm.com
2229792Sandreas.hansson@arm.comExceptionLevel
2239792Sandreas.hansson@arm.comArmSystem::highestEL(ThreadContext *tc)
2249792Sandreas.hansson@arm.com{
2259792Sandreas.hansson@arm.com    return FullSystem? getArmSystem(tc)->highestEL() : EL1;
2269792Sandreas.hansson@arm.com}
2279792Sandreas.hansson@arm.com
22810720Sandreas.hansson@arm.combool
22911156Sandreas.sandberg@arm.comArmSystem::haveEL(ThreadContext *tc, ExceptionLevel el)
23011156Sandreas.sandberg@arm.com{
23112070Snikos.nikoleris@arm.com    switch (el) {
23212070Snikos.nikoleris@arm.com      case EL0:
2339792Sandreas.hansson@arm.com      case EL1:
2349792Sandreas.hansson@arm.com        return true;
2359792Sandreas.hansson@arm.com      case EL2:
2369792Sandreas.hansson@arm.com        return haveVirtualization(tc);
2379792Sandreas.hansson@arm.com      case EL3:
2389792Sandreas.hansson@arm.com        return haveSecurity(tc);
2399792Sandreas.hansson@arm.com      default:
2409792Sandreas.hansson@arm.com        warn("Unimplemented Exception Level\n");
2419792Sandreas.hansson@arm.com        return false;
2429792Sandreas.hansson@arm.com    }
2439792Sandreas.hansson@arm.com}
2449792Sandreas.hansson@arm.com
2459792Sandreas.hansson@arm.comAddr
2469792Sandreas.hansson@arm.comArmSystem::resetAddr64(ThreadContext *tc)
2479792Sandreas.hansson@arm.com{
2489792Sandreas.hansson@arm.com    return getArmSystem(tc)->resetAddr64();
2499792Sandreas.hansson@arm.com}
2509792Sandreas.hansson@arm.com
2519792Sandreas.hansson@arm.comuint8_t
2529792Sandreas.hansson@arm.comArmSystem::physAddrRange(ThreadContext *tc)
2539792Sandreas.hansson@arm.com{
2549792Sandreas.hansson@arm.com    return getArmSystem(tc)->physAddrRange();
2559792Sandreas.hansson@arm.com}
25610884Sandreas.hansson@arm.com
25710884Sandreas.hansson@arm.comAddr
2589792Sandreas.hansson@arm.comArmSystem::physAddrMask(ThreadContext *tc)
2599792Sandreas.hansson@arm.com{
2609792Sandreas.hansson@arm.com    return getArmSystem(tc)->physAddrMask();
2619792Sandreas.hansson@arm.com}
2629792Sandreas.hansson@arm.com
2639380SAndreas.Sandberg@ARM.combool
2649380SAndreas.Sandberg@ARM.comArmSystem::haveLargeAsid64(ThreadContext *tc)
2659380SAndreas.Sandberg@ARM.com{
2669380SAndreas.Sandberg@ARM.com    return getArmSystem(tc)->haveLargeAsid64();
2679380SAndreas.Sandberg@ARM.com}
2689380SAndreas.Sandberg@ARM.com
2699380SAndreas.Sandberg@ARM.comArmSystem *
2709380SAndreas.Sandberg@ARM.comArmSystemParams::create()
2719380SAndreas.Sandberg@ARM.com{
27212070Snikos.nikoleris@arm.com    return new ArmSystem(this);
27312070Snikos.nikoleris@arm.com}
27412070Snikos.nikoleris@arm.com
27512070Snikos.nikoleris@arm.comvoid
27612070Snikos.nikoleris@arm.comGenericArmSystem::initState()
27712070Snikos.nikoleris@arm.com{
27812070Snikos.nikoleris@arm.com    // Moved from the constructor to here since it relies on the
27912070Snikos.nikoleris@arm.com    // address map being resolved in the interconnect
28012070Snikos.nikoleris@arm.com
28112070Snikos.nikoleris@arm.com    // Call the initialisation of the super class
28212070Snikos.nikoleris@arm.com    ArmSystem::initState();
2839826Sandreas.hansson@arm.com}
28412070Snikos.nikoleris@arm.com
28512070Snikos.nikoleris@arm.comGenericArmSystem *
28612070Snikos.nikoleris@arm.comGenericArmSystemParams::create()
28712070Snikos.nikoleris@arm.com{
2889380SAndreas.Sandberg@ARM.com
2899380SAndreas.Sandberg@ARM.com    return new GenericArmSystem(this);
2909380SAndreas.Sandberg@ARM.com}
2919380SAndreas.Sandberg@ARM.com