system.cc revision 9332
17585SAli.Saidi@arm.com/* 29332Sdam.sunwoo@arm.com * Copyright (c) 2010-2012 ARM Limited 37585SAli.Saidi@arm.com * All rights reserved 47585SAli.Saidi@arm.com * 57585SAli.Saidi@arm.com * The license below extends only to copyright in the software and shall 67585SAli.Saidi@arm.com * not be construed as granting a license to any other intellectual 77585SAli.Saidi@arm.com * property including but not limited to intellectual property relating 87585SAli.Saidi@arm.com * to a hardware implementation of the functionality of the software 97585SAli.Saidi@arm.com * licensed hereunder. You may use the software subject to the license 107585SAli.Saidi@arm.com * terms below provided that you ensure that this notice is replicated 117585SAli.Saidi@arm.com * unmodified and in its entirety in all distributions of the software, 127585SAli.Saidi@arm.com * modified or unmodified, in source code or in binary form. 137585SAli.Saidi@arm.com * 147585SAli.Saidi@arm.com * Copyright (c) 2002-2006 The Regents of The University of Michigan 157585SAli.Saidi@arm.com * All rights reserved. 167585SAli.Saidi@arm.com * 177585SAli.Saidi@arm.com * Redistribution and use in source and binary forms, with or without 187585SAli.Saidi@arm.com * modification, are permitted provided that the following conditions are 197585SAli.Saidi@arm.com * met: redistributions of source code must retain the above copyright 207585SAli.Saidi@arm.com * notice, this list of conditions and the following disclaimer; 217585SAli.Saidi@arm.com * redistributions in binary form must reproduce the above copyright 227585SAli.Saidi@arm.com * notice, this list of conditions and the following disclaimer in the 237585SAli.Saidi@arm.com * documentation and/or other materials provided with the distribution; 247585SAli.Saidi@arm.com * neither the name of the copyright holders nor the names of its 257585SAli.Saidi@arm.com * contributors may be used to endorse or promote products derived from 267585SAli.Saidi@arm.com * this software without specific prior written permission. 277585SAli.Saidi@arm.com * 287585SAli.Saidi@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 297585SAli.Saidi@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 307585SAli.Saidi@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 317585SAli.Saidi@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 327585SAli.Saidi@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 337585SAli.Saidi@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 347585SAli.Saidi@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 357585SAli.Saidi@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 367585SAli.Saidi@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 377585SAli.Saidi@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 387585SAli.Saidi@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 397585SAli.Saidi@arm.com * 407585SAli.Saidi@arm.com * Authors: Ali Saidi 417585SAli.Saidi@arm.com */ 427585SAli.Saidi@arm.com 437585SAli.Saidi@arm.com#include "arch/arm/linux/atag.hh" 447585SAli.Saidi@arm.com#include "arch/arm/linux/system.hh" 458229Snate@binkert.org#include "arch/arm/isa_traits.hh" 467723SAli.Saidi@ARM.com#include "arch/arm/utility.hh" 479332Sdam.sunwoo@arm.com#include "arch/generic/linux/threadinfo.hh" 487585SAli.Saidi@arm.com#include "base/loader/object_file.hh" 497585SAli.Saidi@arm.com#include "base/loader/symtab.hh" 509332Sdam.sunwoo@arm.com#include "cpu/base.hh" 519332Sdam.sunwoo@arm.com#include "cpu/pc_event.hh" 527723SAli.Saidi@ARM.com#include "cpu/thread_context.hh" 538245Snate@binkert.org#include "debug/Loader.hh" 548143SAli.Saidi@ARM.com#include "kern/linux/events.hh" 558706Sandreas.hansson@arm.com#include "mem/fs_translating_port_proxy.hh" 567585SAli.Saidi@arm.com#include "mem/physical.hh" 579332Sdam.sunwoo@arm.com#include "sim/stat_control.hh" 587585SAli.Saidi@arm.com 597585SAli.Saidi@arm.comusing namespace ArmISA; 608143SAli.Saidi@ARM.comusing namespace Linux; 617585SAli.Saidi@arm.com 627585SAli.Saidi@arm.comLinuxArmSystem::LinuxArmSystem(Params *p) 639332Sdam.sunwoo@arm.com : ArmSystem(p), 649332Sdam.sunwoo@arm.com enableContextSwitchStatsDump(p->enable_context_switch_stats_dump) 657585SAli.Saidi@arm.com{ 668885SAli.Saidi@ARM.com#ifndef NDEBUG 678885SAli.Saidi@ARM.com kernelPanicEvent = addKernelFuncEvent<BreakPCEvent>("panic"); 688885SAli.Saidi@ARM.com if (!kernelPanicEvent) 698885SAli.Saidi@ARM.com panic("could not find kernel symbol \'panic\'"); 708885SAli.Saidi@ARM.com#endif 718885SAli.Saidi@ARM.com 728885SAli.Saidi@ARM.com // With ARM udelay() is #defined to __udelay 738885SAli.Saidi@ARM.com Addr addr = 0; 748885SAli.Saidi@ARM.com if (kernelSymtab->findAddress("__udelay", addr)) { 758885SAli.Saidi@ARM.com uDelaySkipEvent = new UDelayEvent(&pcEventQueue, "__udelay", 768885SAli.Saidi@ARM.com fixFuncEventAddr(addr), 1000, 0); 778885SAli.Saidi@ARM.com } else { 788885SAli.Saidi@ARM.com panic("couldn't find kernel symbol \'udelay\'"); 798885SAli.Saidi@ARM.com } 808885SAli.Saidi@ARM.com 818885SAli.Saidi@ARM.com // constant arguments to udelay() have some precomputation done ahead of 828885SAli.Saidi@ARM.com // time. Constant comes from code. 838885SAli.Saidi@ARM.com if (kernelSymtab->findAddress("__const_udelay", addr)) { 848885SAli.Saidi@ARM.com constUDelaySkipEvent = new UDelayEvent(&pcEventQueue, "__const_udelay", 858885SAli.Saidi@ARM.com fixFuncEventAddr(addr), 1000, 107374); 868885SAli.Saidi@ARM.com } else { 878885SAli.Saidi@ARM.com panic("couldn't find kernel symbol \'udelay\'"); 888885SAli.Saidi@ARM.com } 898885SAli.Saidi@ARM.com 908885SAli.Saidi@ARM.com secDataPtrAddr = 0; 918885SAli.Saidi@ARM.com secDataAddr = 0; 928885SAli.Saidi@ARM.com penReleaseAddr = 0; 938885SAli.Saidi@ARM.com kernelSymtab->findAddress("__secondary_data", secDataPtrAddr); 948885SAli.Saidi@ARM.com kernelSymtab->findAddress("secondary_data", secDataAddr); 958885SAli.Saidi@ARM.com kernelSymtab->findAddress("pen_release", penReleaseAddr); 968885SAli.Saidi@ARM.com 978885SAli.Saidi@ARM.com secDataPtrAddr &= ~ULL(0x7F); 988885SAli.Saidi@ARM.com secDataAddr &= ~ULL(0x7F); 998885SAli.Saidi@ARM.com penReleaseAddr &= ~ULL(0x7F); 1008706Sandreas.hansson@arm.com} 1018706Sandreas.hansson@arm.com 1028706Sandreas.hansson@arm.combool 1038706Sandreas.hansson@arm.comLinuxArmSystem::adderBootUncacheable(Addr a) 1048706Sandreas.hansson@arm.com{ 1058706Sandreas.hansson@arm.com Addr block = a & ~ULL(0x7F); 1068706Sandreas.hansson@arm.com if (block == secDataPtrAddr || block == secDataAddr || 1078706Sandreas.hansson@arm.com block == penReleaseAddr) 1088706Sandreas.hansson@arm.com return true; 1098706Sandreas.hansson@arm.com return false; 1108706Sandreas.hansson@arm.com} 1118706Sandreas.hansson@arm.com 1128706Sandreas.hansson@arm.comvoid 1138706Sandreas.hansson@arm.comLinuxArmSystem::initState() 1148706Sandreas.hansson@arm.com{ 1158706Sandreas.hansson@arm.com // Moved from the constructor to here since it relies on the 1168706Sandreas.hansson@arm.com // address map being resolved in the interconnect 1178706Sandreas.hansson@arm.com 1188706Sandreas.hansson@arm.com // Call the initialisation of the super class 1198706Sandreas.hansson@arm.com ArmSystem::initState(); 1208706Sandreas.hansson@arm.com 1217585SAli.Saidi@arm.com // Load symbols at physical address, we might not want 1228997Sdam.sunwoo@arm.com // to do this permanently, for but early bootup work 1238997Sdam.sunwoo@arm.com // it is helpful. 1248997Sdam.sunwoo@arm.com if (params()->early_kernel_symbols) { 1258997Sdam.sunwoo@arm.com kernel->loadGlobalSymbols(kernelSymtab, loadAddrMask); 1268997Sdam.sunwoo@arm.com kernel->loadGlobalSymbols(debugSymbolTable, loadAddrMask); 1278997Sdam.sunwoo@arm.com } 1287585SAli.Saidi@arm.com 1297585SAli.Saidi@arm.com // Setup boot data structure 1309261Sdam.sunwoo@arm.com Addr addr = 0; 1319261Sdam.sunwoo@arm.com // Check if the kernel image has a symbol that tells us it supports 1329261Sdam.sunwoo@arm.com // device trees. 1339261Sdam.sunwoo@arm.com bool kernel_has_fdt_support = 1349261Sdam.sunwoo@arm.com kernelSymtab->findAddress("unflatten_device_tree", addr); 1359261Sdam.sunwoo@arm.com bool dtb_file_specified = params()->dtb_filename != ""; 1367585SAli.Saidi@arm.com 1379261Sdam.sunwoo@arm.com if (kernel_has_fdt_support && dtb_file_specified) { 1389261Sdam.sunwoo@arm.com // Kernel supports flattened device tree and dtb file specified. 1399261Sdam.sunwoo@arm.com // Using Device Tree Blob to describe system configuration. 1409261Sdam.sunwoo@arm.com inform("Loading DTB file: %s\n", params()->dtb_filename); 1419261Sdam.sunwoo@arm.com 1429261Sdam.sunwoo@arm.com ObjectFile *dtb_file = createObjectFile(params()->dtb_filename, true); 1439261Sdam.sunwoo@arm.com if (!dtb_file) { 1449261Sdam.sunwoo@arm.com fatal("couldn't load DTB file: %s\n", params()->dtb_filename); 1459261Sdam.sunwoo@arm.com } 1469261Sdam.sunwoo@arm.com dtb_file->setTextBase(params()->atags_addr); 1479261Sdam.sunwoo@arm.com dtb_file->loadSections(physProxy); 1489261Sdam.sunwoo@arm.com delete dtb_file; 1499261Sdam.sunwoo@arm.com } else { 1509261Sdam.sunwoo@arm.com // Using ATAGS 1519261Sdam.sunwoo@arm.com // Warn if the kernel supports FDT and we haven't specified one 1529261Sdam.sunwoo@arm.com if (kernel_has_fdt_support) { 1539261Sdam.sunwoo@arm.com assert(!dtb_file_specified); 1549261Sdam.sunwoo@arm.com warn("Kernel supports device tree, but no DTB file specified\n"); 1559261Sdam.sunwoo@arm.com } 1569261Sdam.sunwoo@arm.com // Warn if the kernel doesn't support FDT and we have specified one 1579261Sdam.sunwoo@arm.com if (dtb_file_specified) { 1589261Sdam.sunwoo@arm.com assert(!kernel_has_fdt_support); 1599261Sdam.sunwoo@arm.com warn("DTB file specified, but no device tree support in kernel\n"); 1609261Sdam.sunwoo@arm.com } 1619261Sdam.sunwoo@arm.com 1629290Sandreas.hansson@arm.com AtagCore ac; 1639290Sandreas.hansson@arm.com ac.flags(1); // read-only 1649290Sandreas.hansson@arm.com ac.pagesize(8192); 1659290Sandreas.hansson@arm.com ac.rootdev(0); 1669261Sdam.sunwoo@arm.com 1679261Sdam.sunwoo@arm.com AddrRangeList atagRanges = physmem.getConfAddrRanges(); 1689261Sdam.sunwoo@arm.com if (atagRanges.size() != 1) { 1699261Sdam.sunwoo@arm.com fatal("Expected a single ATAG memory entry but got %d\n", 1709261Sdam.sunwoo@arm.com atagRanges.size()); 1719261Sdam.sunwoo@arm.com } 1729290Sandreas.hansson@arm.com AtagMem am; 1739290Sandreas.hansson@arm.com am.memSize(atagRanges.begin()->size()); 1749290Sandreas.hansson@arm.com am.memStart(atagRanges.begin()->start); 1759261Sdam.sunwoo@arm.com 1769290Sandreas.hansson@arm.com AtagCmdline ad; 1779290Sandreas.hansson@arm.com ad.cmdline(params()->boot_osflags); 1789261Sdam.sunwoo@arm.com 1799290Sandreas.hansson@arm.com DPRINTF(Loader, "boot command line %d bytes: %s\n", 1809290Sandreas.hansson@arm.com ad.size() <<2, params()->boot_osflags.c_str()); 1819261Sdam.sunwoo@arm.com 1829290Sandreas.hansson@arm.com AtagNone an; 1839261Sdam.sunwoo@arm.com 1849290Sandreas.hansson@arm.com uint32_t size = ac.size() + am.size() + ad.size() + an.size(); 1859261Sdam.sunwoo@arm.com uint32_t offset = 0; 1869261Sdam.sunwoo@arm.com uint8_t *boot_data = new uint8_t[size << 2]; 1879261Sdam.sunwoo@arm.com 1889290Sandreas.hansson@arm.com offset += ac.copyOut(boot_data + offset); 1899290Sandreas.hansson@arm.com offset += am.copyOut(boot_data + offset); 1909290Sandreas.hansson@arm.com offset += ad.copyOut(boot_data + offset); 1919290Sandreas.hansson@arm.com offset += an.copyOut(boot_data + offset); 1929261Sdam.sunwoo@arm.com 1939261Sdam.sunwoo@arm.com DPRINTF(Loader, "Boot atags was %d bytes in total\n", size << 2); 1949261Sdam.sunwoo@arm.com DDUMP(Loader, boot_data, size << 2); 1959261Sdam.sunwoo@arm.com 1969261Sdam.sunwoo@arm.com physProxy.writeBlob(params()->atags_addr, boot_data, size << 2); 1979290Sandreas.hansson@arm.com 1989290Sandreas.hansson@arm.com delete[] boot_data; 1998931Sandreas.hansson@arm.com } 2007585SAli.Saidi@arm.com 2018286SAli.Saidi@ARM.com for (int i = 0; i < threadContexts.size(); i++) { 2028286SAli.Saidi@ARM.com threadContexts[i]->setIntReg(0, 0); 2038286SAli.Saidi@ARM.com threadContexts[i]->setIntReg(1, params()->machine_type); 2048870SAli.Saidi@ARM.com threadContexts[i]->setIntReg(2, params()->atags_addr); 2058286SAli.Saidi@ARM.com } 2067585SAli.Saidi@arm.com} 2077585SAli.Saidi@arm.com 2087585SAli.Saidi@arm.comLinuxArmSystem::~LinuxArmSystem() 2097585SAli.Saidi@arm.com{ 2108143SAli.Saidi@ARM.com if (uDelaySkipEvent) 2118143SAli.Saidi@ARM.com delete uDelaySkipEvent; 2128143SAli.Saidi@ARM.com if (constUDelaySkipEvent) 2138143SAli.Saidi@ARM.com delete constUDelaySkipEvent; 2149332Sdam.sunwoo@arm.com 2159332Sdam.sunwoo@arm.com if (dumpStatsPCEvent) 2169332Sdam.sunwoo@arm.com delete dumpStatsPCEvent; 2177585SAli.Saidi@arm.com} 2187585SAli.Saidi@arm.com 2197585SAli.Saidi@arm.comLinuxArmSystem * 2207585SAli.Saidi@arm.comLinuxArmSystemParams::create() 2217585SAli.Saidi@arm.com{ 2227585SAli.Saidi@arm.com return new LinuxArmSystem(this); 2237585SAli.Saidi@arm.com} 2249332Sdam.sunwoo@arm.com 2259332Sdam.sunwoo@arm.comvoid 2269332Sdam.sunwoo@arm.comLinuxArmSystem::startup() 2279332Sdam.sunwoo@arm.com{ 2289332Sdam.sunwoo@arm.com if (enableContextSwitchStatsDump) { 2299332Sdam.sunwoo@arm.com dumpStatsPCEvent = addKernelFuncEvent<DumpStatsPCEvent>("__switch_to"); 2309332Sdam.sunwoo@arm.com if (!dumpStatsPCEvent) 2319332Sdam.sunwoo@arm.com panic("dumpStatsPCEvent not created!"); 2329332Sdam.sunwoo@arm.com 2339332Sdam.sunwoo@arm.com std::string task_filename = "tasks.txt"; 2349332Sdam.sunwoo@arm.com taskFile = simout.create(name() + "." + task_filename); 2359332Sdam.sunwoo@arm.com 2369332Sdam.sunwoo@arm.com for (int i = 0; i < _numContexts; i++) { 2379332Sdam.sunwoo@arm.com ThreadContext *tc = threadContexts[i]; 2389332Sdam.sunwoo@arm.com uint32_t pid = tc->getCpuPtr()->getPid(); 2399332Sdam.sunwoo@arm.com if (pid != Request::invldPid) { 2409332Sdam.sunwoo@arm.com mapPid(tc, pid); 2419332Sdam.sunwoo@arm.com tc->getCpuPtr()->taskId(taskMap[pid]); 2429332Sdam.sunwoo@arm.com } 2439332Sdam.sunwoo@arm.com } 2449332Sdam.sunwoo@arm.com } 2459332Sdam.sunwoo@arm.com} 2469332Sdam.sunwoo@arm.com 2479332Sdam.sunwoo@arm.comvoid 2489332Sdam.sunwoo@arm.comLinuxArmSystem::mapPid(ThreadContext *tc, uint32_t pid) 2499332Sdam.sunwoo@arm.com{ 2509332Sdam.sunwoo@arm.com // Create a new unique identifier for this pid 2519332Sdam.sunwoo@arm.com std::map<uint32_t, uint32_t>::iterator itr = taskMap.find(pid); 2529332Sdam.sunwoo@arm.com if (itr == taskMap.end()) { 2539332Sdam.sunwoo@arm.com uint32_t map_size = taskMap.size(); 2549332Sdam.sunwoo@arm.com if (map_size > ContextSwitchTaskId::MaxNormalTaskId + 1) { 2559332Sdam.sunwoo@arm.com warn_once("Error out of identifiers for cache occupancy stats"); 2569332Sdam.sunwoo@arm.com taskMap[pid] = ContextSwitchTaskId::Unknown; 2579332Sdam.sunwoo@arm.com } else { 2589332Sdam.sunwoo@arm.com taskMap[pid] = map_size; 2599332Sdam.sunwoo@arm.com } 2609332Sdam.sunwoo@arm.com } 2619332Sdam.sunwoo@arm.com} 2629332Sdam.sunwoo@arm.com 2639332Sdam.sunwoo@arm.com/** This function is called whenever the the kernel function 2649332Sdam.sunwoo@arm.com * "__switch_to" is called to change running tasks. 2659332Sdam.sunwoo@arm.com * 2669332Sdam.sunwoo@arm.com * r0 = task_struct of the previously running process 2679332Sdam.sunwoo@arm.com * r1 = task_info of the previously running process 2689332Sdam.sunwoo@arm.com * r2 = task_info of the next process to run 2699332Sdam.sunwoo@arm.com */ 2709332Sdam.sunwoo@arm.comvoid 2719332Sdam.sunwoo@arm.comDumpStatsPCEvent::process(ThreadContext *tc) 2729332Sdam.sunwoo@arm.com{ 2739332Sdam.sunwoo@arm.com Linux::ThreadInfo ti(tc); 2749332Sdam.sunwoo@arm.com Addr task_descriptor = tc->readIntReg(2); 2759332Sdam.sunwoo@arm.com uint32_t pid = ti.curTaskPID(task_descriptor); 2769332Sdam.sunwoo@arm.com uint32_t tgid = ti.curTaskTGID(task_descriptor); 2779332Sdam.sunwoo@arm.com std::string next_task_str = ti.curTaskName(task_descriptor); 2789332Sdam.sunwoo@arm.com 2799332Sdam.sunwoo@arm.com // Streamline treats pid == -1 as the kernel process. 2809332Sdam.sunwoo@arm.com // Also pid == 0 implies idle process (except during Linux boot) 2819332Sdam.sunwoo@arm.com int32_t mm = ti.curTaskMm(task_descriptor); 2829332Sdam.sunwoo@arm.com bool is_kernel = (mm == 0); 2839332Sdam.sunwoo@arm.com if (is_kernel && (pid != 0)) { 2849332Sdam.sunwoo@arm.com pid = -1; 2859332Sdam.sunwoo@arm.com tgid = -1; 2869332Sdam.sunwoo@arm.com next_task_str = "kernel"; 2879332Sdam.sunwoo@arm.com } 2889332Sdam.sunwoo@arm.com 2899332Sdam.sunwoo@arm.com LinuxArmSystem* sys = dynamic_cast<LinuxArmSystem *>(tc->getSystemPtr()); 2909332Sdam.sunwoo@arm.com if (!sys) { 2919332Sdam.sunwoo@arm.com panic("System is not LinuxArmSystem while getting Linux process info!"); 2929332Sdam.sunwoo@arm.com } 2939332Sdam.sunwoo@arm.com std::map<uint32_t, uint32_t>& taskMap = sys->taskMap; 2949332Sdam.sunwoo@arm.com 2959332Sdam.sunwoo@arm.com // Create a new unique identifier for this pid 2969332Sdam.sunwoo@arm.com sys->mapPid(tc, pid); 2979332Sdam.sunwoo@arm.com 2989332Sdam.sunwoo@arm.com // Set cpu task id, output process info, and dump stats 2999332Sdam.sunwoo@arm.com tc->getCpuPtr()->taskId(taskMap[pid]); 3009332Sdam.sunwoo@arm.com tc->getCpuPtr()->setPid(pid); 3019332Sdam.sunwoo@arm.com 3029332Sdam.sunwoo@arm.com std::ostream* taskFile = sys->taskFile; 3039332Sdam.sunwoo@arm.com 3049332Sdam.sunwoo@arm.com // Task file is read by cache occupancy plotting script or 3059332Sdam.sunwoo@arm.com // Streamline conversion script. 3069332Sdam.sunwoo@arm.com ccprintf(*taskFile, 3079332Sdam.sunwoo@arm.com "tick=%lld %d cpu_id=%d next_pid=%d next_tgid=%d next_task=%s\n", 3089332Sdam.sunwoo@arm.com curTick(), taskMap[pid], tc->cpuId(), (int) pid, (int) tgid, 3099332Sdam.sunwoo@arm.com next_task_str); 3109332Sdam.sunwoo@arm.com taskFile->flush(); 3119332Sdam.sunwoo@arm.com 3129332Sdam.sunwoo@arm.com // Dump and reset statistics 3139332Sdam.sunwoo@arm.com Stats::schedStatEvent(true, true, curTick(), 0); 3149332Sdam.sunwoo@arm.com} 3159332Sdam.sunwoo@arm.com 316