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