system.cc revision 10822
112SN/A/*
21762SN/A * Copyright (c) 2010-2013 ARM Limited
312SN/A * All rights reserved
412SN/A *
512SN/A * The license below extends only to copyright in the software and shall
612SN/A * not be construed as granting a license to any other intellectual
712SN/A * property including but not limited to intellectual property relating
812SN/A * to a hardware implementation of the functionality of the software
912SN/A * licensed hereunder.  You may use the software subject to the license
1012SN/A * terms below provided that you ensure that this notice is replicated
1112SN/A * unmodified and in its entirety in all distributions of the software,
1212SN/A * modified or unmodified, in source code or in binary form.
1312SN/A *
1412SN/A * Copyright (c) 2002-2006 The Regents of The University of Michigan
1512SN/A * All rights reserved.
1612SN/A *
1712SN/A * Redistribution and use in source and binary forms, with or without
1812SN/A * modification, are permitted provided that the following conditions are
1912SN/A * met: redistributions of source code must retain the above copyright
2012SN/A * notice, this list of conditions and the following disclaimer;
2112SN/A * redistributions in binary form must reproduce the above copyright
2212SN/A * notice, this list of conditions and the following disclaimer in the
2312SN/A * documentation and/or other materials provided with the distribution;
2412SN/A * neither the name of the copyright holders nor the names of its
2512SN/A * contributors may be used to endorse or promote products derived from
2612SN/A * this software without specific prior written permission.
272665Ssaidi@eecs.umich.edu *
282665Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
292665Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3012SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3112SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
325616Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3312SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3412SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3556SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
364484Sbinkertn@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
378229Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
382439SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
397676Snate@binkert.org *
408232Snate@binkert.org * Authors: Ali Saidi
412423SN/A */
428229Snate@binkert.org
432423SN/A#include "arch/arm/linux/atag.hh"
4412SN/A#include "arch/arm/linux/system.hh"
4512SN/A#include "arch/arm/isa_traits.hh"
4612SN/A#include "arch/arm/utility.hh"
4712SN/A#include "arch/generic/linux/threadinfo.hh"
4812SN/A#include "base/loader/dtb_object.hh"
49443SN/A#include "base/loader/object_file.hh"
50443SN/A#include "base/loader/symtab.hh"
512207SN/A#include "cpu/base.hh"
522207SN/A#include "cpu/pc_event.hh"
53443SN/A#include "cpu/thread_context.hh"
54468SN/A#include "debug/Loader.hh"
551708SN/A#include "kern/linux/events.hh"
561708SN/A#include "mem/fs_translating_port_proxy.hh"
57443SN/A#include "mem/physical.hh"
58468SN/A#include "sim/stat_control.hh"
59443SN/A
60468SN/Ausing namespace ArmISA;
61443SN/Ausing namespace Linux;
62443SN/A
63468SN/ALinuxArmSystem::LinuxArmSystem(Params *p)
64468SN/A    : GenericArmSystem(p), dumpStatsPCEvent(nullptr),
65443SN/A      enableContextSwitchStatsDump(p->enable_context_switch_stats_dump),
66443SN/A      taskFile(nullptr), kernelPanicEvent(nullptr), kernelOopsEvent(nullptr)
67443SN/A{
682476SN/A    if (p->panic_on_panic) {
692207SN/A        kernelPanicEvent = addKernelFuncEventOrPanic<PanicPCEvent>(
702207SN/A            "panic", "Kernel panic in simulated kernel");
712207SN/A    } else {
722207SN/A#ifndef NDEBUG
732207SN/A        kernelPanicEvent = addKernelFuncEventOrPanic<BreakPCEvent>("panic");
744111Sgblack@eecs.umich.edu#endif
754111Sgblack@eecs.umich.edu    }
762620SN/A
774111Sgblack@eecs.umich.edu    if (p->panic_on_oops) {
784111Sgblack@eecs.umich.edu        kernelOopsEvent = addKernelFuncEventOrPanic<PanicPCEvent>(
794111Sgblack@eecs.umich.edu            "oops_exit", "Kernel oops in guest");
804111Sgblack@eecs.umich.edu    }
814111Sgblack@eecs.umich.edu
822207SN/A    // With ARM udelay() is #defined to __udelay
832207SN/A    // newer kernels use __loop_udelay and __loop_const_udelay symbols
845383Sgblack@eecs.umich.edu    uDelaySkipEvent = addKernelFuncEvent<UDelayEvent>(
855383Sgblack@eecs.umich.edu        "__loop_udelay", "__udelay", 1000, 0);
865383Sgblack@eecs.umich.edu    if(!uDelaySkipEvent)
875383Sgblack@eecs.umich.edu        uDelaySkipEvent = addKernelFuncEventOrPanic<UDelayEvent>(
885383Sgblack@eecs.umich.edu         "__udelay", "__udelay", 1000, 0);
895383Sgblack@eecs.umich.edu
905383Sgblack@eecs.umich.edu    // constant arguments to udelay() have some precomputation done ahead of
914166Sgblack@eecs.umich.edu    // time. Constant comes from code.
924166Sgblack@eecs.umich.edu    constUDelaySkipEvent = addKernelFuncEvent<UDelayEvent>(
935874Sgblack@eecs.umich.edu        "__loop_const_udelay", "__const_udelay", 1000, 107374);
945874Sgblack@eecs.umich.edu    if(!constUDelaySkipEvent)
955874Sgblack@eecs.umich.edu        constUDelaySkipEvent = addKernelFuncEventOrPanic<UDelayEvent>(
965874Sgblack@eecs.umich.edu         "__const_udelay", "__const_udelay", 1000, 107374);
972207SN/A
982207SN/A}
995335Shines@cs.fsu.edu
1007095Sgblack@eecs.umich.eduvoid
1017095Sgblack@eecs.umich.eduLinuxArmSystem::initState()
1027095Sgblack@eecs.umich.edu{
1037095Sgblack@eecs.umich.edu    // Moved from the constructor to here since it relies on the
1047095Sgblack@eecs.umich.edu    // address map being resolved in the interconnect
1056691Stjones1@inf.ed.ac.uk
1066691Stjones1@inf.ed.ac.uk    // Call the initialisation of the super class
1076691Stjones1@inf.ed.ac.uk    GenericArmSystem::initState();
1086691Stjones1@inf.ed.ac.uk
1096691Stjones1@inf.ed.ac.uk    // Load symbols at physical address, we might not want
1106691Stjones1@inf.ed.ac.uk    // to do this permanently, for but early bootup work
1116691Stjones1@inf.ed.ac.uk    // it is helpful.
1126691Stjones1@inf.ed.ac.uk    if (params()->early_kernel_symbols) {
1136691Stjones1@inf.ed.ac.uk        kernel->loadGlobalSymbols(kernelSymtab, loadAddrMask);
1146691Stjones1@inf.ed.ac.uk        kernel->loadGlobalSymbols(debugSymbolTable, loadAddrMask);
1156691Stjones1@inf.ed.ac.uk    }
1166691Stjones1@inf.ed.ac.uk
1176691Stjones1@inf.ed.ac.uk    // Setup boot data structure
1182207SN/A    Addr addr = 0;
1192600SN/A    // Check if the kernel image has a symbol that tells us it supports
1202207SN/A    // device trees.
1212207SN/A    bool kernel_has_fdt_support =
1222207SN/A        kernelSymtab->findAddress("unflatten_device_tree", addr);
1232207SN/A    bool dtb_file_specified = params()->dtb_filename != "";
1242207SN/A
1252207SN/A    if (kernel_has_fdt_support && dtb_file_specified) {
1262238SN/A        // Kernel supports flattened device tree and dtb file specified.
1272207SN/A        // Using Device Tree Blob to describe system configuration.
1282207SN/A        inform("Loading DTB file: %s at address %#x\n", params()->dtb_filename,
1292207SN/A                params()->atags_addr + loadAddrOffset);
1302207SN/A
1312207SN/A        ObjectFile *dtb_file = createObjectFile(params()->dtb_filename, true);
1322238SN/A        if (!dtb_file) {
1332207SN/A            fatal("couldn't load DTB file: %s\n", params()->dtb_filename);
1342207SN/A        }
1352238SN/A
1366392Ssaidi@eecs.umich.edu        DtbObject *_dtb_file = dynamic_cast<DtbObject*>(dtb_file);
1376392Ssaidi@eecs.umich.edu
1386392Ssaidi@eecs.umich.edu        if (_dtb_file) {
1392207SN/A            if (!_dtb_file->addBootCmdLine(params()->boot_osflags.c_str(),
1402207SN/A                                           params()->boot_osflags.size())) {
1412207SN/A                warn("couldn't append bootargs to DTB file: %s\n",
1422207SN/A                     params()->dtb_filename);
1432238SN/A            }
1442238SN/A        } else {
1452600SN/A            warn("dtb_file cast failed; couldn't append bootargs "
1462238SN/A                 "to DTB file: %s\n", params()->dtb_filename);
1472238SN/A        }
1482238SN/A
1492238SN/A        dtb_file->setTextBase(params()->atags_addr + loadAddrOffset);
1502238SN/A        dtb_file->loadSections(physProxy);
1512238SN/A        delete dtb_file;
1522238SN/A    } else {
1532238SN/A        // Using ATAGS
1542238SN/A        // Warn if the kernel supports FDT and we haven't specified one
1552238SN/A        if (kernel_has_fdt_support) {
1562600SN/A            assert(!dtb_file_specified);
1572238SN/A            warn("Kernel supports device tree, but no DTB file specified\n");
1582238SN/A        }
1592238SN/A        // Warn if the kernel doesn't support FDT and we have specified one
1602238SN/A        if (dtb_file_specified) {
1612238SN/A            assert(!kernel_has_fdt_support);
1622238SN/A            warn("DTB file specified, but no device tree support in kernel\n");
1632238SN/A        }
1642238SN/A
1652238SN/A        AtagCore ac;
1662238SN/A        ac.flags(1); // read-only
1672238SN/A        ac.pagesize(8192);
1682238SN/A        ac.rootdev(0);
1692238SN/A
1702238SN/A        AddrRangeList atagRanges = physmem.getConfAddrRanges();
1712238SN/A        if (atagRanges.size() != 1) {
1722238SN/A            fatal("Expected a single ATAG memory entry but got %d\n",
1732238SN/A                  atagRanges.size());
1742238SN/A        }
1752238SN/A        AtagMem am;
1762238SN/A        am.memSize(atagRanges.begin()->size());
1772238SN/A        am.memStart(atagRanges.begin()->start());
1782238SN/A
1792600SN/A        AtagCmdline ad;
1802600SN/A        ad.cmdline(params()->boot_osflags);
1812600SN/A
1822600SN/A        DPRINTF(Loader, "boot command line %d bytes: %s\n",
1832600SN/A                ad.size() <<2, params()->boot_osflags.c_str());
1842238SN/A
1852238SN/A        AtagNone an;
1862238SN/A
1872472SN/A        uint32_t size = ac.size() + am.size() + ad.size() + an.size();
1882976Sgblack@eecs.umich.edu        uint32_t offset = 0;
1892976Sgblack@eecs.umich.edu        uint8_t *boot_data = new uint8_t[size << 2];
1902976Sgblack@eecs.umich.edu
1912976Sgblack@eecs.umich.edu        offset += ac.copyOut(boot_data + offset);
1922976Sgblack@eecs.umich.edu        offset += am.copyOut(boot_data + offset);
1932976Sgblack@eecs.umich.edu        offset += ad.copyOut(boot_data + offset);
1942976Sgblack@eecs.umich.edu        offset += an.copyOut(boot_data + offset);
1952976Sgblack@eecs.umich.edu
1962976Sgblack@eecs.umich.edu        DPRINTF(Loader, "Boot atags was %d bytes in total\n", size << 2);
1972976Sgblack@eecs.umich.edu        DDUMP(Loader, boot_data, size << 2);
1982976Sgblack@eecs.umich.edu
1992976Sgblack@eecs.umich.edu        physProxy.writeBlob(params()->atags_addr + loadAddrOffset, boot_data,
2002976Sgblack@eecs.umich.edu                size << 2);
2012976Sgblack@eecs.umich.edu
2022976Sgblack@eecs.umich.edu        delete[] boot_data;
2032976Sgblack@eecs.umich.edu    }
2042976Sgblack@eecs.umich.edu
2052976Sgblack@eecs.umich.edu    // Kernel boot requirements to set up r0, r1 and r2 in ARMv7
2062976Sgblack@eecs.umich.edu    for (int i = 0; i < threadContexts.size(); i++) {
2072976Sgblack@eecs.umich.edu        threadContexts[i]->setIntReg(0, 0);
2082976Sgblack@eecs.umich.edu        threadContexts[i]->setIntReg(1, params()->machine_type);
2095143Sgblack@eecs.umich.edu        threadContexts[i]->setIntReg(2, params()->atags_addr + loadAddrOffset);
2102976Sgblack@eecs.umich.edu    }
2112976Sgblack@eecs.umich.edu}
2122976Sgblack@eecs.umich.edu
2132976Sgblack@eecs.umich.eduLinuxArmSystem::~LinuxArmSystem()
2142976Sgblack@eecs.umich.edu{
2152976Sgblack@eecs.umich.edu    if (uDelaySkipEvent)
2162976Sgblack@eecs.umich.edu        delete uDelaySkipEvent;
2172976Sgblack@eecs.umich.edu    if (constUDelaySkipEvent)
2182238SN/A        delete constUDelaySkipEvent;
2192976Sgblack@eecs.umich.edu
22012SN/A    if (dumpStatsPCEvent)
22112SN/A        delete dumpStatsPCEvent;
22212SN/A}
22312SN/A
22412SN/ALinuxArmSystem *
225360SN/ALinuxArmSystemParams::create()
226360SN/A{
227360SN/A    return new LinuxArmSystem(this);
228443SN/A}
22912SN/A
230443SN/Avoid
231443SN/ALinuxArmSystem::startup()
23212SN/A{
233468SN/A    if (enableContextSwitchStatsDump) {
2341708SN/A        dumpStatsPCEvent = addKernelFuncEvent<DumpStatsPCEvent>("__switch_to");
2351708SN/A        if (!dumpStatsPCEvent)
23612SN/A           panic("dumpStatsPCEvent not created!");
237468SN/A
238443SN/A        std::string task_filename = "tasks.txt";
239468SN/A        taskFile = simout.create(name() + "." + task_filename);
240443SN/A
24112SN/A        for (int i = 0; i < _numContexts; i++) {
242468SN/A            ThreadContext *tc = threadContexts[i];
243468SN/A            uint32_t pid = tc->getCpuPtr()->getPid();
244443SN/A            if (pid != Request::invldPid) {
24512SN/A                mapPid(tc, pid);
24612SN/A                tc->getCpuPtr()->taskId(taskMap[pid]);
247468SN/A            }
24812SN/A        }
249468SN/A    }
250468SN/A}
2519186SAli.Saidi@ARM.com
252468SN/Avoid
2535090Sgblack@eecs.umich.eduLinuxArmSystem::mapPid(ThreadContext *tc, uint32_t pid)
2545090Sgblack@eecs.umich.edu{
2555090Sgblack@eecs.umich.edu    // Create a new unique identifier for this pid
2565090Sgblack@eecs.umich.edu    std::map<uint32_t, uint32_t>::iterator itr = taskMap.find(pid);
2575090Sgblack@eecs.umich.edu    if (itr == taskMap.end()) {
2585090Sgblack@eecs.umich.edu        uint32_t map_size = taskMap.size();
2595090Sgblack@eecs.umich.edu        if (map_size > ContextSwitchTaskId::MaxNormalTaskId + 1) {
2605090Sgblack@eecs.umich.edu            warn_once("Error out of identifiers for cache occupancy stats");
2615090Sgblack@eecs.umich.edu            taskMap[pid] = ContextSwitchTaskId::Unknown;
2625090Sgblack@eecs.umich.edu        } else {
2635090Sgblack@eecs.umich.edu            taskMap[pid] = map_size;
2645090Sgblack@eecs.umich.edu        }
2655090Sgblack@eecs.umich.edu    }
2665090Sgblack@eecs.umich.edu}
2675090Sgblack@eecs.umich.edu
2685090Sgblack@eecs.umich.edu/** This function is called whenever the the kernel function
2695090Sgblack@eecs.umich.edu *  "__switch_to" is called to change running tasks.
2708350Sgblack@eecs.umich.edu *
2718350Sgblack@eecs.umich.edu *  r0 = task_struct of the previously running process
2728350Sgblack@eecs.umich.edu *  r1 = task_info of the previously running process
2738350Sgblack@eecs.umich.edu *  r2 = task_info of the next process to run
2748350Sgblack@eecs.umich.edu */
2758350Sgblack@eecs.umich.eduvoid
2768350Sgblack@eecs.umich.eduDumpStatsPCEvent::process(ThreadContext *tc)
2778350Sgblack@eecs.umich.edu{
2788350Sgblack@eecs.umich.edu    Linux::ThreadInfo ti(tc);
2798350Sgblack@eecs.umich.edu    Addr task_descriptor = tc->readIntReg(2);
2808350Sgblack@eecs.umich.edu    uint32_t pid = ti.curTaskPID(task_descriptor);
2818350Sgblack@eecs.umich.edu    uint32_t tgid = ti.curTaskTGID(task_descriptor);
2828350Sgblack@eecs.umich.edu    std::string next_task_str = ti.curTaskName(task_descriptor);
2838350Sgblack@eecs.umich.edu
2845090Sgblack@eecs.umich.edu    // Streamline treats pid == -1 as the kernel process.
2855090Sgblack@eecs.umich.edu    // Also pid == 0 implies idle process (except during Linux boot)
2865090Sgblack@eecs.umich.edu    int32_t mm = ti.curTaskMm(task_descriptor);
2875090Sgblack@eecs.umich.edu    bool is_kernel = (mm == 0);
2885090Sgblack@eecs.umich.edu    if (is_kernel && (pid != 0)) {
2895090Sgblack@eecs.umich.edu        pid = -1;
2905090Sgblack@eecs.umich.edu        tgid = -1;
2915090Sgblack@eecs.umich.edu        next_task_str = "kernel";
292468SN/A    }
293468SN/A
294468SN/A    LinuxArmSystem* sys = dynamic_cast<LinuxArmSystem *>(tc->getSystemPtr());
2955090Sgblack@eecs.umich.edu    if (!sys) {
296468SN/A        panic("System is not LinuxArmSystem while getting Linux process info!");
297468SN/A    }
298468SN/A    std::map<uint32_t, uint32_t>& taskMap = sys->taskMap;
299468SN/A
300468SN/A    // Create a new unique identifier for this pid
301468SN/A    sys->mapPid(tc, pid);
3025090Sgblack@eecs.umich.edu
3035143Sgblack@eecs.umich.edu    // Set cpu task id, output process info, and dump stats
3045143Sgblack@eecs.umich.edu    tc->getCpuPtr()->taskId(taskMap[pid]);
3055090Sgblack@eecs.umich.edu    tc->getCpuPtr()->setPid(pid);
3065143Sgblack@eecs.umich.edu
3075090Sgblack@eecs.umich.edu    std::ostream* taskFile = sys->taskFile;
3085090Sgblack@eecs.umich.edu
3095090Sgblack@eecs.umich.edu    // Task file is read by cache occupancy plotting script or
3105090Sgblack@eecs.umich.edu    // Streamline conversion script.
3115090Sgblack@eecs.umich.edu    ccprintf(*taskFile,
3125152Sgblack@eecs.umich.edu             "tick=%lld %d cpu_id=%d next_pid=%d next_tgid=%d next_task=%s\n",
3135152Sgblack@eecs.umich.edu             curTick(), taskMap[pid], tc->cpuId(), (int) pid, (int) tgid,
3145143Sgblack@eecs.umich.edu             next_task_str);
315468SN/A    taskFile->flush();
3162420SN/A
3175152Sgblack@eecs.umich.edu    // Dump and reset statistics
3185152Sgblack@eecs.umich.edu    Stats::schedStatEvent(true, true, curTick(), 0);
3195143Sgblack@eecs.umich.edu}
320468SN/A
3212420SN/A