system.cc revision 10554
12689Sktlim@umich.edu/* 22689Sktlim@umich.edu * Copyright (c) 2011-2014 ARM Limited 32689Sktlim@umich.edu * All rights reserved 42689Sktlim@umich.edu * 52689Sktlim@umich.edu * The license below extends only to copyright in the software and shall 62689Sktlim@umich.edu * not be construed as granting a license to any other intellectual 72689Sktlim@umich.edu * property including but not limited to intellectual property relating 82689Sktlim@umich.edu * to a hardware implementation of the functionality of the software 92689Sktlim@umich.edu * licensed hereunder. You may use the software subject to the license 102689Sktlim@umich.edu * terms below provided that you ensure that this notice is replicated 112689Sktlim@umich.edu * unmodified and in its entirety in all distributions of the software, 122689Sktlim@umich.edu * modified or unmodified, in source code or in binary form. 132689Sktlim@umich.edu * 142689Sktlim@umich.edu * Copyright (c) 2003-2006 The Regents of The University of Michigan 152689Sktlim@umich.edu * Copyright (c) 2011 Regents of the University of California 162689Sktlim@umich.edu * All rights reserved. 172689Sktlim@umich.edu * 182689Sktlim@umich.edu * Redistribution and use in source and binary forms, with or without 192689Sktlim@umich.edu * modification, are permitted provided that the following conditions are 202689Sktlim@umich.edu * met: redistributions of source code must retain the above copyright 212689Sktlim@umich.edu * notice, this list of conditions and the following disclaimer; 222689Sktlim@umich.edu * redistributions in binary form must reproduce the above copyright 232689Sktlim@umich.edu * notice, this list of conditions and the following disclaimer in the 242689Sktlim@umich.edu * documentation and/or other materials provided with the distribution; 252689Sktlim@umich.edu * neither the name of the copyright holders nor the names of its 262689Sktlim@umich.edu * contributors may be used to endorse or promote products derived from 272689Sktlim@umich.edu * this software without specific prior written permission. 282689Sktlim@umich.edu * 292689Sktlim@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 302689Sktlim@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 312689Sktlim@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 322689Sktlim@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 332689Sktlim@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 342521SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 353960Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 364194Ssaidi@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 371070SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 381070SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 392521SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 402680Sktlim@umich.edu * 416658Snate@binkert.org * Authors: Steve Reinhardt 426658Snate@binkert.org * Lisa Hsu 432521SN/A * Nathan Binkert 442522SN/A * Ali Saidi 452037SN/A * Rick Strong 4656SN/A */ 475512SMichael.Adler@intel.com 486658Snate@binkert.org#include "arch/remote_gdb.hh" 492378SN/A#include "arch/utility.hh" 502521SN/A#include "base/loader/object_file.hh" 512378SN/A#include "base/loader/symtab.hh" 527723SAli.Saidi@ARM.com#include "base/str.hh" 534762Snate@binkert.org#include "base/trace.hh" 544762Snate@binkert.org#include "cpu/thread_context.hh" 552378SN/A#include "debug/Loader.hh" 562SN/A#include "debug/WorkItems.hh" 572SN/A#include "mem/abstract_mem.hh" 582107SN/A#include "mem/physical.hh" 592SN/A#include "params/System.hh" 602SN/A#include "sim/byteswap.hh" 612SN/A#include "sim/debug.hh" 622SN/A#include "sim/full_system.hh" 632SN/A#include "sim/system.hh" 641070SN/A 655714Shsul@eecs.umich.edu/** 662378SN/A * To avoid linking errors with LTO, only include the header if we 672521SN/A * actually have a definition. 687580SAli.Saidi@arm.com */ 692378SN/A#if THE_ISA != NULL_ISA 707770SAli.Saidi@ARM.com#include "kern/kernel_stats.hh" 717770SAli.Saidi@ARM.com#endif 722378SN/A 732902Ssaidi@eecs.umich.eduusing namespace std; 742SN/Ausing namespace TheISA; 751070SN/A 761070SN/Avector<System *> System::systemList; 771070SN/A 782378SN/Aint System::numSystemsRunning = 0; 791070SN/A 804838Ssaidi@eecs.umich.eduSystem::System(Params *p) 814838Ssaidi@eecs.umich.edu : MemObject(p), _systemPort("system_port", this), 821070SN/A _numContexts(0), 832520SN/A pagePtr(0), 842520SN/A init_param(p->init_param), 852520SN/A physProxy(_systemPort, p->cache_line_size), 862520SN/A kernelSymtab(nullptr), 872520SN/A kernel(nullptr), 887723SAli.Saidi@ARM.com loadAddrMask(p->load_addr_mask), 892520SN/A loadAddrOffset(p->load_offset), 907723SAli.Saidi@ARM.com nextPID(0), 917723SAli.Saidi@ARM.com physmem(name() + ".physmem", p->memories), 922520SN/A memoryMode(p->mem_mode), 937723SAli.Saidi@ARM.com _cacheLineSize(p->cache_line_size), 942521SN/A workItemsBegin(0), 957723SAli.Saidi@ARM.com workItemsEnd(0), 967723SAli.Saidi@ARM.com numWorkIds(p->num_work_ids), 972521SN/A _params(p), 982520SN/A totalNumInsts(0), 991070SN/A instEventQueue("system instruction-based event queue") 1002158SN/A{ 1011070SN/A // add self to global system list 1024762Snate@binkert.org systemList.push_back(this); 1035823Ssaidi@eecs.umich.edu 1043812Ssaidi@eecs.umich.edu if (FullSystem) { 1053812Ssaidi@eecs.umich.edu kernelSymtab = new SymbolTable; 1063812Ssaidi@eecs.umich.edu if (!debugSymbolTable) 1074762Snate@binkert.org debugSymbolTable = new SymbolTable; 1085823Ssaidi@eecs.umich.edu } 1095222Sksewell@umich.edu 1103812Ssaidi@eecs.umich.edu // check if the cache line size is a value known to work 1114762Snate@binkert.org if (!(_cacheLineSize == 16 || _cacheLineSize == 32 || 1121070SN/A _cacheLineSize == 64 || _cacheLineSize == 128)) 1133812Ssaidi@eecs.umich.edu warn_once("Cache line size is neither 16, 32, 64 nor 128 bytes.\n"); 1147723SAli.Saidi@ARM.com 1151070SN/A // Get the generic system master IDs 1163812Ssaidi@eecs.umich.edu MasterID tmp_id M5_VAR_USED; 1173812Ssaidi@eecs.umich.edu tmp_id = getMasterId("writebacks"); 1183812Ssaidi@eecs.umich.edu assert(tmp_id == Request::wbMasterId); 1193812Ssaidi@eecs.umich.edu tmp_id = getMasterId("functional"); 1201070SN/A assert(tmp_id == Request::funcMasterId); 1213812Ssaidi@eecs.umich.edu tmp_id = getMasterId("interrupt"); 1223812Ssaidi@eecs.umich.edu assert(tmp_id == Request::intMasterId); 1235823Ssaidi@eecs.umich.edu 1241070SN/A if (FullSystem) { 1253812Ssaidi@eecs.umich.edu if (params()->kernel == "") { 1265823Ssaidi@eecs.umich.edu inform("No kernel set for full system simulation. " 1271070SN/A "Assuming you know what you're doing\n"); 1283812Ssaidi@eecs.umich.edu } else { 1295823Ssaidi@eecs.umich.edu // Get the kernel code 1301074SN/A kernel = createObjectFile(params()->kernel); 1313812Ssaidi@eecs.umich.edu inform("kernel located at: %s", params()->kernel); 1325823Ssaidi@eecs.umich.edu 1331074SN/A if (kernel == NULL) 1343812Ssaidi@eecs.umich.edu fatal("Could not load kernel file %s", params()->kernel); 1353812Ssaidi@eecs.umich.edu 1363812Ssaidi@eecs.umich.edu // setup entry points 1373812Ssaidi@eecs.umich.edu kernelStart = kernel->textBase(); 1383812Ssaidi@eecs.umich.edu kernelEnd = kernel->bssBase() + kernel->bssSize(); 1392378SN/A kernelEntry = kernel->entryPoint(); 1402378SN/A 1411070SN/A // load symbols 142878SN/A if (!kernel->loadGlobalSymbols(kernelSymtab)) 1432SN/A fatal("could not load kernel symbols\n"); 1442SN/A 1452SN/A if (!kernel->loadLocalSymbols(kernelSymtab)) 1462SN/A fatal("could not load kernel local symbols\n"); 1472378SN/A 1481070SN/A if (!kernel->loadGlobalSymbols(debugSymbolTable)) 1491070SN/A fatal("could not load kernel symbols\n"); 1502378SN/A 1512378SN/A if (!kernel->loadLocalSymbols(debugSymbolTable)) 1522378SN/A fatal("could not load kernel local symbols\n"); 1532378SN/A 1542SN/A // Loading only needs to happen once and after memory system is 1552SN/A // connected so it will happen in initState() 1562901Ssaidi@eecs.umich.edu } 1574762Snate@binkert.org } 1582901Ssaidi@eecs.umich.edu 1592901Ssaidi@eecs.umich.edu // increment the number of running systms 1602901Ssaidi@eecs.umich.edu numSystemsRunning++; 1612901Ssaidi@eecs.umich.edu 1622901Ssaidi@eecs.umich.edu // Set back pointers to the system in all memories 1633960Sgblack@eecs.umich.edu for (int x = 0; x < params()->memories.size(); x++) 1643960Sgblack@eecs.umich.edu params()->memories[x]->system(this); 1654095Sbinkertn@umich.edu} 1664095Sbinkertn@umich.edu 1674095Sbinkertn@umich.eduSystem::~System() 1683960Sgblack@eecs.umich.edu{ 1693960Sgblack@eecs.umich.edu delete kernelSymtab; 1707445Ssteve.reinhardt@amd.com delete kernel; 1717445Ssteve.reinhardt@amd.com 1727445Ssteve.reinhardt@amd.com for (uint32_t j = 0; j < numWorkIds; j++) 1737445Ssteve.reinhardt@amd.com delete workItemStats[j]; 1747445Ssteve.reinhardt@amd.com} 1757445Ssteve.reinhardt@amd.com 1767445Ssteve.reinhardt@amd.comvoid 177180SN/ASystem::init() 1785718Shsul@eecs.umich.edu{ 1792SN/A // check that the system port is connected 1805712Shsul@eecs.umich.edu if (!_systemPort.isConnected()) 1815718Shsul@eecs.umich.edu panic("System port on %s is not connected.\n", name()); 1825718Shsul@eecs.umich.edu} 1835718Shsul@eecs.umich.edu 1845718Shsul@eecs.umich.eduBaseMasterPort& 1855718Shsul@eecs.umich.eduSystem::getMasterPort(const std::string &if_name, PortID idx) 1865718Shsul@eecs.umich.edu{ 1875718Shsul@eecs.umich.edu // no need to distinguish at the moment (besides checking) 1885718Shsul@eecs.umich.edu return _systemPort; 1895718Shsul@eecs.umich.edu} 1905718Shsul@eecs.umich.edu 1915718Shsul@eecs.umich.eduvoid 1925718Shsul@eecs.umich.eduSystem::setMemoryMode(Enums::MemoryMode mode) 1931806SN/A{ 1941806SN/A assert(getDrainState() == Drainable::Drained); 1952680Sktlim@umich.edu memoryMode = mode; 1965823Ssaidi@eecs.umich.edu} 1971806SN/A 1982680Sktlim@umich.edubool System::breakpoint() 1995714Shsul@eecs.umich.edu{ 2001070SN/A if (remoteGDB.size()) 2015512SMichael.Adler@intel.com return remoteGDB[0]->breakpoint(); 2027445Ssteve.reinhardt@amd.com return false; 2034095Sbinkertn@umich.edu} 2045512SMichael.Adler@intel.com 2054095Sbinkertn@umich.edu/** 2067445Ssteve.reinhardt@amd.com * Setting rgdb_wait to a positive integer waits for a remote debugger to 2074095Sbinkertn@umich.edu * connect to that context ID before continuing. This should really 2084095Sbinkertn@umich.edu be a parameter on the CPU object or something... 2091070SN/A */ 2104095Sbinkertn@umich.eduint rgdb_wait = -1; 2114095Sbinkertn@umich.edu 2124095Sbinkertn@umich.eduint 2134095Sbinkertn@umich.eduSystem::registerThreadContext(ThreadContext *tc, int assigned) 2144095Sbinkertn@umich.edu{ 2151070SN/A int id; 2161070SN/A if (assigned == -1) { 2171806SN/A for (id = 0; id < threadContexts.size(); id++) { 218180SN/A if (!threadContexts[id]) 21975SN/A break; 2206029Ssteve.reinhardt@amd.com } 2216029Ssteve.reinhardt@amd.com 2226029Ssteve.reinhardt@amd.com if (threadContexts.size() <= id) 2236029Ssteve.reinhardt@amd.com threadContexts.resize(id + 1); 2246029Ssteve.reinhardt@amd.com } else { 2256029Ssteve.reinhardt@amd.com if (threadContexts.size() <= assigned) 2266029Ssteve.reinhardt@amd.com threadContexts.resize(assigned + 1); 2276029Ssteve.reinhardt@amd.com id = assigned; 2286029Ssteve.reinhardt@amd.com } 2296029Ssteve.reinhardt@amd.com 2306029Ssteve.reinhardt@amd.com if (threadContexts[id]) 231180SN/A fatal("Cannot have two CPUs with the same id (%d)\n", id); 2327733SAli.Saidi@ARM.com 2331129SN/A threadContexts[id] = tc; 2345713Shsul@eecs.umich.edu _numContexts++; 2352114SN/A 2362680Sktlim@umich.edu#if THE_ISA != NULL_ISA 2374194Ssaidi@eecs.umich.edu int port = getRemoteGDBPort(); 2385713Shsul@eecs.umich.edu if (port) { 2391129SN/A RemoteGDB *rgdb = new RemoteGDB(this, tc); 2401129SN/A GDBListener *gdbl = new GDBListener(rgdb, port + id); 2411129SN/A gdbl->listen(); 2425713Shsul@eecs.umich.edu 243180SN/A if (rgdb_wait != -1 && rgdb_wait == id) 2445713Shsul@eecs.umich.edu gdbl->accept(); 2452680Sktlim@umich.edu 2465713Shsul@eecs.umich.edu if (remoteGDB.size() <= id) { 247180SN/A remoteGDB.resize(id + 1); 248180SN/A } 2495713Shsul@eecs.umich.edu 2505713Shsul@eecs.umich.edu remoteGDB[id] = rgdb; 2515713Shsul@eecs.umich.edu } 2522SN/A#endif 2532SN/A 2542378SN/A activeCpus.push_back(false); 2552378SN/A 2562378SN/A return id; 2572378SN/A} 2587770SAli.Saidi@ARM.com 2597770SAli.Saidi@ARM.comint 2603162Ssaidi@eecs.umich.eduSystem::numRunningContexts() 2613162Ssaidi@eecs.umich.edu{ 2622378SN/A int running = 0; 2632378SN/A for (int i = 0; i < _numContexts; ++i) { 2645795Ssaidi@eecs.umich.edu if (threadContexts[i]->status() != ThreadContext::Halted) 2655795Ssaidi@eecs.umich.edu ++running; 2665795Ssaidi@eecs.umich.edu } 2675795Ssaidi@eecs.umich.edu return running; 2685795Ssaidi@eecs.umich.edu} 2695795Ssaidi@eecs.umich.edu 2705795Ssaidi@eecs.umich.eduvoid 2715795Ssaidi@eecs.umich.eduSystem::initState() 2725795Ssaidi@eecs.umich.edu{ 2735795Ssaidi@eecs.umich.edu if (FullSystem) { 2747770SAli.Saidi@ARM.com for (int i = 0; i < threadContexts.size(); i++) 2755795Ssaidi@eecs.umich.edu TheISA::startupCPU(threadContexts[i], i); 2765795Ssaidi@eecs.umich.edu // Moved from the constructor to here since it relies on the 2772378SN/A // address map being resolved in the interconnect 2782378SN/A /** 2791070SN/A * Load the kernel code into memory 2801070SN/A */ 2811070SN/A if (params()->kernel != "") { 2822378SN/A if (params()->kernel_addr_check) { 2831984SN/A // Validate kernel mapping before loading binary 2845183Ssaidi@eecs.umich.edu if (!(isMemAddr((kernelStart & loadAddrMask) + 2857770SAli.Saidi@ARM.com loadAddrOffset) && 2867770SAli.Saidi@ARM.com isMemAddr((kernelEnd & loadAddrMask) + 2875183Ssaidi@eecs.umich.edu loadAddrOffset))) { 2881070SN/A fatal("Kernel is mapped to invalid location (not memory). " 2891070SN/A "kernelStart 0x(%x) - kernelEnd 0x(%x) %#x:%#x\n", 2901070SN/A kernelStart, 2911070SN/A kernelEnd, (kernelStart & loadAddrMask) + 2921070SN/A loadAddrOffset, 2931070SN/A (kernelEnd & loadAddrMask) + loadAddrOffset); 2942378SN/A } 2951984SN/A } 2965183Ssaidi@eecs.umich.edu // Load program sections into memory 2977770SAli.Saidi@ARM.com kernel->loadSections(physProxy, loadAddrMask, loadAddrOffset); 2987770SAli.Saidi@ARM.com 2995183Ssaidi@eecs.umich.edu DPRINTF(Loader, "Kernel start = %#x\n", kernelStart); 3001070SN/A DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd); 3012SN/A DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry); 3022SN/A DPRINTF(Loader, "Kernel loaded...\n"); 3032SN/A } 3042SN/A } 3052SN/A 3062SN/A activeCpus.clear(); 3072SN/A} 3082SN/A 3092SN/Avoid 3102SN/ASystem::replaceThreadContext(ThreadContext *tc, int context_id) 3112SN/A{ 3122SN/A if (context_id >= threadContexts.size()) { 3132SN/A panic("replaceThreadContext: bad id, %d >= %d\n", 3142SN/A context_id, threadContexts.size()); 3152SN/A } 3162SN/A 3172SN/A threadContexts[context_id] = tc; 3182SN/A if (context_id < remoteGDB.size()) 3192902Ssaidi@eecs.umich.edu remoteGDB[context_id]->replaceThreadContext(tc); 3202902Ssaidi@eecs.umich.edu} 3212902Ssaidi@eecs.umich.edu 3224762Snate@binkert.orgAddr 3232424SN/ASystem::allocPhysPages(int npages) 3244762Snate@binkert.org{ 3254762Snate@binkert.org Addr return_addr = pagePtr << PageShift; 3262424SN/A pagePtr += npages; 3275530Snate@binkert.org 3282424SN/A Addr next_return_addr = pagePtr << PageShift; 3292424SN/A 3302424SN/A AddrRange m5opRange(0xffff0000, 0xffffffff); 331 if (m5opRange.contains(next_return_addr)) { 332 warn("Reached m5ops MMIO region\n"); 333 return_addr = 0xffffffff; 334 pagePtr = 0xffffffff >> PageShift; 335 } 336 337 if ((pagePtr << PageShift) > physmem.totalSize()) 338 fatal("Out of memory, please increase size of physical memory."); 339 return return_addr; 340} 341 342Addr 343System::memSize() const 344{ 345 return physmem.totalSize(); 346} 347 348Addr 349System::freeMemSize() const 350{ 351 return physmem.totalSize() - (pagePtr << PageShift); 352} 353 354bool 355System::isMemAddr(Addr addr) const 356{ 357 return physmem.isMemAddr(addr); 358} 359 360unsigned int 361System::drain(DrainManager *dm) 362{ 363 setDrainState(Drainable::Drained); 364 return 0; 365} 366 367void 368System::drainResume() 369{ 370 Drainable::drainResume(); 371 totalNumInsts = 0; 372} 373 374void 375System::serialize(ostream &os) 376{ 377 if (FullSystem) 378 kernelSymtab->serialize("kernel_symtab", os); 379 SERIALIZE_SCALAR(pagePtr); 380 SERIALIZE_SCALAR(nextPID); 381 serializeSymtab(os); 382 383 // also serialize the memories in the system 384 nameOut(os, csprintf("%s.physmem", name())); 385 physmem.serialize(os); 386} 387 388 389void 390System::unserialize(Checkpoint *cp, const string §ion) 391{ 392 if (FullSystem) 393 kernelSymtab->unserialize("kernel_symtab", cp, section); 394 UNSERIALIZE_SCALAR(pagePtr); 395 UNSERIALIZE_SCALAR(nextPID); 396 unserializeSymtab(cp, section); 397 398 // also unserialize the memories in the system 399 physmem.unserialize(cp, csprintf("%s.physmem", name())); 400} 401 402void 403System::regStats() 404{ 405 for (uint32_t j = 0; j < numWorkIds ; j++) { 406 workItemStats[j] = new Stats::Histogram(); 407 stringstream namestr; 408 ccprintf(namestr, "work_item_type%d", j); 409 workItemStats[j]->init(20) 410 .name(name() + "." + namestr.str()) 411 .desc("Run time stat for" + namestr.str()) 412 .prereq(*workItemStats[j]); 413 } 414} 415 416void 417System::workItemEnd(uint32_t tid, uint32_t workid) 418{ 419 std::pair<uint32_t,uint32_t> p(tid, workid); 420 if (!lastWorkItemStarted.count(p)) 421 return; 422 423 Tick samp = curTick() - lastWorkItemStarted[p]; 424 DPRINTF(WorkItems, "Work item end: %d\t%d\t%lld\n", tid, workid, samp); 425 426 if (workid >= numWorkIds) 427 fatal("Got workid greater than specified in system configuration\n"); 428 429 workItemStats[workid]->sample(samp); 430 lastWorkItemStarted.erase(p); 431} 432 433void 434System::printSystems() 435{ 436 ios::fmtflags flags(cerr.flags()); 437 438 vector<System *>::iterator i = systemList.begin(); 439 vector<System *>::iterator end = systemList.end(); 440 for (; i != end; ++i) { 441 System *sys = *i; 442 cerr << "System " << sys->name() << ": " << hex << sys << endl; 443 } 444 445 cerr.flags(flags); 446} 447 448void 449printSystems() 450{ 451 System::printSystems(); 452} 453 454MasterID 455System::getMasterId(std::string master_name) 456{ 457 // strip off system name if the string starts with it 458 if (startswith(master_name, name())) 459 master_name = master_name.erase(0, name().size() + 1); 460 461 // CPUs in switch_cpus ask for ids again after switching 462 for (int i = 0; i < masterIds.size(); i++) { 463 if (masterIds[i] == master_name) { 464 return i; 465 } 466 } 467 468 // Verify that the statistics haven't been enabled yet 469 // Otherwise objects will have sized their stat buckets and 470 // they will be too small 471 472 if (Stats::enabled()) { 473 fatal("Can't request a masterId after regStats(). " 474 "You must do so in init().\n"); 475 } 476 477 masterIds.push_back(master_name); 478 479 return masterIds.size() - 1; 480} 481 482std::string 483System::getMasterName(MasterID master_id) 484{ 485 if (master_id >= masterIds.size()) 486 fatal("Invalid master_id passed to getMasterName()\n"); 487 488 return masterIds[master_id]; 489} 490 491System * 492SystemParams::create() 493{ 494 return new System(this); 495} 496