system.cc revision 9850
15222Sksewell@umich.edu/* 25268Sksewell@umich.edu * Copyright (c) 2011-2013 ARM Limited 35254Sksewell@umich.edu * All rights reserved 45254Sksewell@umich.edu * 55222Sksewell@umich.edu * The license below extends only to copyright in the software and shall 65254Sksewell@umich.edu * not be construed as granting a license to any other intellectual 75254Sksewell@umich.edu * property including but not limited to intellectual property relating 85254Sksewell@umich.edu * to a hardware implementation of the functionality of the software 95254Sksewell@umich.edu * licensed hereunder. You may use the software subject to the license 105254Sksewell@umich.edu * terms below provided that you ensure that this notice is replicated 115254Sksewell@umich.edu * unmodified and in its entirety in all distributions of the software, 125254Sksewell@umich.edu * modified or unmodified, in source code or in binary form. 135254Sksewell@umich.edu * 145254Sksewell@umich.edu * Copyright (c) 2003-2006 The Regents of The University of Michigan 155254Sksewell@umich.edu * Copyright (c) 2011 Regents of the University of California 165222Sksewell@umich.edu * All rights reserved. 175254Sksewell@umich.edu * 185254Sksewell@umich.edu * Redistribution and use in source and binary forms, with or without 195254Sksewell@umich.edu * modification, are permitted provided that the following conditions are 205254Sksewell@umich.edu * met: redistributions of source code must retain the above copyright 215254Sksewell@umich.edu * notice, this list of conditions and the following disclaimer; 225254Sksewell@umich.edu * redistributions in binary form must reproduce the above copyright 235254Sksewell@umich.edu * notice, this list of conditions and the following disclaimer in the 245254Sksewell@umich.edu * documentation and/or other materials provided with the distribution; 255254Sksewell@umich.edu * neither the name of the copyright holders nor the names of its 265254Sksewell@umich.edu * contributors may be used to endorse or promote products derived from 275254Sksewell@umich.edu * this software without specific prior written permission. 285222Sksewell@umich.edu * 295254Sksewell@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 305254Sksewell@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 315222Sksewell@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 325222Sksewell@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 335222Sksewell@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 345222Sksewell@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 355222Sksewell@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 365222Sksewell@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 375222Sksewell@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 385222Sksewell@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 395222Sksewell@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 405222Sksewell@umich.edu * 415222Sksewell@umich.edu * Authors: Steve Reinhardt 425222Sksewell@umich.edu * Lisa Hsu 435222Sksewell@umich.edu * Nathan Binkert 445222Sksewell@umich.edu * Ali Saidi 455222Sksewell@umich.edu * Rick Strong 465222Sksewell@umich.edu */ 475222Sksewell@umich.edu 485222Sksewell@umich.edu#include "arch/isa_traits.hh" 495222Sksewell@umich.edu#include "arch/remote_gdb.hh" 505222Sksewell@umich.edu#include "arch/utility.hh" 515222Sksewell@umich.edu#include "base/loader/object_file.hh" 525222Sksewell@umich.edu#include "base/loader/symtab.hh" 535222Sksewell@umich.edu#include "base/str.hh" 545222Sksewell@umich.edu#include "base/trace.hh" 555222Sksewell@umich.edu#include "config/the_isa.hh" 565222Sksewell@umich.edu#include "cpu/thread_context.hh" 575222Sksewell@umich.edu#include "debug/Loader.hh" 585222Sksewell@umich.edu#include "debug/WorkItems.hh" 595222Sksewell@umich.edu#include "kern/kernel_stats.hh" 605222Sksewell@umich.edu#include "mem/abstract_mem.hh" 615222Sksewell@umich.edu#include "mem/physical.hh" 625222Sksewell@umich.edu#include "params/System.hh" 635222Sksewell@umich.edu#include "sim/byteswap.hh" 645222Sksewell@umich.edu#include "sim/debug.hh" 655222Sksewell@umich.edu#include "sim/full_system.hh" 665222Sksewell@umich.edu#include "sim/system.hh" 675222Sksewell@umich.edu 685222Sksewell@umich.eduusing namespace std; 695222Sksewell@umich.eduusing namespace TheISA; 705222Sksewell@umich.edu 715222Sksewell@umich.eduvector<System *> System::systemList; 725222Sksewell@umich.edu 735222Sksewell@umich.eduint System::numSystemsRunning = 0; 745222Sksewell@umich.edu 755222Sksewell@umich.eduSystem::System(Params *p) 765222Sksewell@umich.edu : MemObject(p), _systemPort("system_port", this), 775222Sksewell@umich.edu _numContexts(0), 785222Sksewell@umich.edu pagePtr(0), 795222Sksewell@umich.edu init_param(p->init_param), 805222Sksewell@umich.edu physProxy(_systemPort, p->cache_line_size), 815222Sksewell@umich.edu loadAddrMask(p->load_addr_mask), 825222Sksewell@umich.edu nextPID(0), 835222Sksewell@umich.edu physmem(name() + ".physmem", p->memories), 845222Sksewell@umich.edu memoryMode(p->mem_mode), 855222Sksewell@umich.edu _cacheLineSize(p->cache_line_size), 865222Sksewell@umich.edu workItemsBegin(0), 875222Sksewell@umich.edu workItemsEnd(0), 885222Sksewell@umich.edu numWorkIds(p->num_work_ids), 895222Sksewell@umich.edu _params(p), 905222Sksewell@umich.edu totalNumInsts(0), 915222Sksewell@umich.edu instEventQueue("system instruction-based event queue") 925222Sksewell@umich.edu{ 935222Sksewell@umich.edu // add self to global system list 945222Sksewell@umich.edu systemList.push_back(this); 955222Sksewell@umich.edu 965222Sksewell@umich.edu if (FullSystem) { 975222Sksewell@umich.edu kernelSymtab = new SymbolTable; 985222Sksewell@umich.edu if (!debugSymbolTable) 995222Sksewell@umich.edu debugSymbolTable = new SymbolTable; 1005222Sksewell@umich.edu } 1015222Sksewell@umich.edu 1025222Sksewell@umich.edu // check if the cache line size is a value known to work 1035222Sksewell@umich.edu if (!(_cacheLineSize == 16 || _cacheLineSize == 32 || 1045222Sksewell@umich.edu _cacheLineSize == 64 || _cacheLineSize == 128)) 1055222Sksewell@umich.edu warn_once("Cache line size is neither 16, 32, 64 nor 128 bytes.\n"); 1065222Sksewell@umich.edu 1075222Sksewell@umich.edu // Get the generic system master IDs 1085222Sksewell@umich.edu MasterID tmp_id M5_VAR_USED; 1095222Sksewell@umich.edu tmp_id = getMasterId("writebacks"); 1105222Sksewell@umich.edu assert(tmp_id == Request::wbMasterId); 1115222Sksewell@umich.edu tmp_id = getMasterId("functional"); 1125222Sksewell@umich.edu assert(tmp_id == Request::funcMasterId); 1135222Sksewell@umich.edu tmp_id = getMasterId("interrupt"); 1145222Sksewell@umich.edu assert(tmp_id == Request::intMasterId); 1155222Sksewell@umich.edu 1165222Sksewell@umich.edu if (FullSystem) { 1175222Sksewell@umich.edu if (params()->kernel == "") { 1185222Sksewell@umich.edu inform("No kernel set for full system simulation. " 1195222Sksewell@umich.edu "Assuming you know what you're doing\n"); 1205222Sksewell@umich.edu 1215222Sksewell@umich.edu kernel = NULL; 1225222Sksewell@umich.edu } else { 1235222Sksewell@umich.edu // Get the kernel code 1245222Sksewell@umich.edu kernel = createObjectFile(params()->kernel); 1255222Sksewell@umich.edu inform("kernel located at: %s", params()->kernel); 1265222Sksewell@umich.edu 1275222Sksewell@umich.edu if (kernel == NULL) 1285222Sksewell@umich.edu fatal("Could not load kernel file %s", params()->kernel); 1295222Sksewell@umich.edu 1305222Sksewell@umich.edu // setup entry points 1315222Sksewell@umich.edu kernelStart = kernel->textBase(); 1325222Sksewell@umich.edu kernelEnd = kernel->bssBase() + kernel->bssSize(); 1335222Sksewell@umich.edu kernelEntry = kernel->entryPoint(); 1345222Sksewell@umich.edu 1355222Sksewell@umich.edu // load symbols 1365222Sksewell@umich.edu if (!kernel->loadGlobalSymbols(kernelSymtab)) 1375543Ssaidi@eecs.umich.edu fatal("could not load kernel symbols\n"); 1385543Ssaidi@eecs.umich.edu 1395543Ssaidi@eecs.umich.edu if (!kernel->loadLocalSymbols(kernelSymtab)) 1405222Sksewell@umich.edu fatal("could not load kernel local symbols\n"); 1415222Sksewell@umich.edu 1425222Sksewell@umich.edu if (!kernel->loadGlobalSymbols(debugSymbolTable)) 1435222Sksewell@umich.edu fatal("could not load kernel symbols\n"); 1445222Sksewell@umich.edu 1455222Sksewell@umich.edu if (!kernel->loadLocalSymbols(debugSymbolTable)) 1465222Sksewell@umich.edu fatal("could not load kernel local symbols\n"); 1475222Sksewell@umich.edu 1485222Sksewell@umich.edu // Loading only needs to happen once and after memory system is 1495222Sksewell@umich.edu // connected so it will happen in initState() 1505222Sksewell@umich.edu } 1515222Sksewell@umich.edu } 1525222Sksewell@umich.edu 1535222Sksewell@umich.edu // increment the number of running systms 1545222Sksewell@umich.edu numSystemsRunning++; 1555222Sksewell@umich.edu 1565222Sksewell@umich.edu // Set back pointers to the system in all memories 1575222Sksewell@umich.edu for (int x = 0; x < params()->memories.size(); x++) 1585222Sksewell@umich.edu params()->memories[x]->system(this); 1595222Sksewell@umich.edu} 1605222Sksewell@umich.edu 1615222Sksewell@umich.eduSystem::~System() 1625222Sksewell@umich.edu{ 1635222Sksewell@umich.edu delete kernelSymtab; 1645222Sksewell@umich.edu delete kernel; 1655222Sksewell@umich.edu 1665222Sksewell@umich.edu for (uint32_t j = 0; j < numWorkIds; j++) 1675222Sksewell@umich.edu delete workItemStats[j]; 1685222Sksewell@umich.edu} 1695222Sksewell@umich.edu 1705222Sksewell@umich.eduvoid 1715222Sksewell@umich.eduSystem::init() 1725222Sksewell@umich.edu{ 1735222Sksewell@umich.edu // check that the system port is connected 1745222Sksewell@umich.edu if (!_systemPort.isConnected()) 1755222Sksewell@umich.edu panic("System port on %s is not connected.\n", name()); 1765222Sksewell@umich.edu} 1775222Sksewell@umich.edu 1785222Sksewell@umich.eduBaseMasterPort& 1795222Sksewell@umich.eduSystem::getMasterPort(const std::string &if_name, PortID idx) 1805222Sksewell@umich.edu{ 1815222Sksewell@umich.edu // no need to distinguish at the moment (besides checking) 1825222Sksewell@umich.edu return _systemPort; 1835222Sksewell@umich.edu} 1845222Sksewell@umich.edu 1855222Sksewell@umich.eduvoid 1865222Sksewell@umich.eduSystem::setMemoryMode(Enums::MemoryMode mode) 1875222Sksewell@umich.edu{ 1885566Snate@binkert.org assert(getDrainState() == Drainable::Drained); 1895222Sksewell@umich.edu memoryMode = mode; 1905222Sksewell@umich.edu} 1915222Sksewell@umich.edu 1925222Sksewell@umich.edubool System::breakpoint() 1935222Sksewell@umich.edu{ 1945222Sksewell@umich.edu if (remoteGDB.size()) 1955222Sksewell@umich.edu return remoteGDB[0]->breakpoint(); 1965222Sksewell@umich.edu return false; 1975222Sksewell@umich.edu} 1985222Sksewell@umich.edu 1995222Sksewell@umich.edu/** 2005222Sksewell@umich.edu * Setting rgdb_wait to a positive integer waits for a remote debugger to 2015222Sksewell@umich.edu * connect to that context ID before continuing. This should really 2025222Sksewell@umich.edu be a parameter on the CPU object or something... 2035222Sksewell@umich.edu */ 2045222Sksewell@umich.eduint rgdb_wait = -1; 2055222Sksewell@umich.edu 2065222Sksewell@umich.eduint 2075222Sksewell@umich.eduSystem::registerThreadContext(ThreadContext *tc, int assigned) 2085222Sksewell@umich.edu{ 2095222Sksewell@umich.edu int id; 2105222Sksewell@umich.edu if (assigned == -1) { 2115222Sksewell@umich.edu for (id = 0; id < threadContexts.size(); id++) { 2125222Sksewell@umich.edu if (!threadContexts[id]) 2135222Sksewell@umich.edu break; 2145222Sksewell@umich.edu } 2155222Sksewell@umich.edu 2165222Sksewell@umich.edu if (threadContexts.size() <= id) 2175222Sksewell@umich.edu threadContexts.resize(id + 1); 2185222Sksewell@umich.edu } else { 2195222Sksewell@umich.edu if (threadContexts.size() <= assigned) 2205222Sksewell@umich.edu threadContexts.resize(assigned + 1); 2215222Sksewell@umich.edu id = assigned; 2225222Sksewell@umich.edu } 223 224 if (threadContexts[id]) 225 fatal("Cannot have two CPUs with the same id (%d)\n", id); 226 227 threadContexts[id] = tc; 228 _numContexts++; 229 230#if THE_ISA != NULL_ISA 231 int port = getRemoteGDBPort(); 232 if (port) { 233 RemoteGDB *rgdb = new RemoteGDB(this, tc); 234 GDBListener *gdbl = new GDBListener(rgdb, port + id); 235 gdbl->listen(); 236 237 if (rgdb_wait != -1 && rgdb_wait == id) 238 gdbl->accept(); 239 240 if (remoteGDB.size() <= id) { 241 remoteGDB.resize(id + 1); 242 } 243 244 remoteGDB[id] = rgdb; 245 } 246#endif 247 248 activeCpus.push_back(false); 249 250 return id; 251} 252 253int 254System::numRunningContexts() 255{ 256 int running = 0; 257 for (int i = 0; i < _numContexts; ++i) { 258 if (threadContexts[i]->status() != ThreadContext::Halted) 259 ++running; 260 } 261 return running; 262} 263 264void 265System::initState() 266{ 267 if (FullSystem) { 268 for (int i = 0; i < threadContexts.size(); i++) 269 TheISA::startupCPU(threadContexts[i], i); 270 // Moved from the constructor to here since it relies on the 271 // address map being resolved in the interconnect 272 /** 273 * Load the kernel code into memory 274 */ 275 if (params()->kernel != "") { 276 // Validate kernel mapping before loading binary 277 if (!(isMemAddr(kernelStart & loadAddrMask) && 278 isMemAddr(kernelEnd & loadAddrMask))) { 279 fatal("Kernel is mapped to invalid location (not memory). " 280 "kernelStart 0x(%x) - kernelEnd 0x(%x)\n", kernelStart, 281 kernelEnd); 282 } 283 // Load program sections into memory 284 kernel->loadSections(physProxy, loadAddrMask); 285 286 DPRINTF(Loader, "Kernel start = %#x\n", kernelStart); 287 DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd); 288 DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry); 289 DPRINTF(Loader, "Kernel loaded...\n"); 290 } 291 } 292 293 activeCpus.clear(); 294} 295 296void 297System::replaceThreadContext(ThreadContext *tc, int context_id) 298{ 299 if (context_id >= threadContexts.size()) { 300 panic("replaceThreadContext: bad id, %d >= %d\n", 301 context_id, threadContexts.size()); 302 } 303 304 threadContexts[context_id] = tc; 305 if (context_id < remoteGDB.size()) 306 remoteGDB[context_id]->replaceThreadContext(tc); 307} 308 309Addr 310System::allocPhysPages(int npages) 311{ 312 Addr return_addr = pagePtr << LogVMPageSize; 313 pagePtr += npages; 314 if ((pagePtr << LogVMPageSize) > physmem.totalSize()) 315 fatal("Out of memory, please increase size of physical memory."); 316 return return_addr; 317} 318 319Addr 320System::memSize() const 321{ 322 return physmem.totalSize(); 323} 324 325Addr 326System::freeMemSize() const 327{ 328 return physmem.totalSize() - (pagePtr << LogVMPageSize); 329} 330 331bool 332System::isMemAddr(Addr addr) const 333{ 334 return physmem.isMemAddr(addr); 335} 336 337unsigned int 338System::drain(DrainManager *dm) 339{ 340 setDrainState(Drainable::Drained); 341 return 0; 342} 343 344void 345System::drainResume() 346{ 347 Drainable::drainResume(); 348 totalNumInsts = 0; 349} 350 351void 352System::serialize(ostream &os) 353{ 354 if (FullSystem) 355 kernelSymtab->serialize("kernel_symtab", os); 356 SERIALIZE_SCALAR(pagePtr); 357 SERIALIZE_SCALAR(nextPID); 358 serializeSymtab(os); 359 360 // also serialize the memories in the system 361 nameOut(os, csprintf("%s.physmem", name())); 362 physmem.serialize(os); 363} 364 365 366void 367System::unserialize(Checkpoint *cp, const string §ion) 368{ 369 if (FullSystem) 370 kernelSymtab->unserialize("kernel_symtab", cp, section); 371 UNSERIALIZE_SCALAR(pagePtr); 372 UNSERIALIZE_SCALAR(nextPID); 373 unserializeSymtab(cp, section); 374 375 // also unserialize the memories in the system 376 physmem.unserialize(cp, csprintf("%s.physmem", name())); 377} 378 379void 380System::regStats() 381{ 382 for (uint32_t j = 0; j < numWorkIds ; j++) { 383 workItemStats[j] = new Stats::Histogram(); 384 stringstream namestr; 385 ccprintf(namestr, "work_item_type%d", j); 386 workItemStats[j]->init(20) 387 .name(name() + "." + namestr.str()) 388 .desc("Run time stat for" + namestr.str()) 389 .prereq(*workItemStats[j]); 390 } 391} 392 393void 394System::workItemEnd(uint32_t tid, uint32_t workid) 395{ 396 std::pair<uint32_t,uint32_t> p(tid, workid); 397 if (!lastWorkItemStarted.count(p)) 398 return; 399 400 Tick samp = curTick() - lastWorkItemStarted[p]; 401 DPRINTF(WorkItems, "Work item end: %d\t%d\t%lld\n", tid, workid, samp); 402 403 if (workid >= numWorkIds) 404 fatal("Got workid greater than specified in system configuration\n"); 405 406 workItemStats[workid]->sample(samp); 407 lastWorkItemStarted.erase(p); 408} 409 410void 411System::printSystems() 412{ 413 vector<System *>::iterator i = systemList.begin(); 414 vector<System *>::iterator end = systemList.end(); 415 for (; i != end; ++i) { 416 System *sys = *i; 417 cerr << "System " << sys->name() << ": " << hex << sys << endl; 418 } 419} 420 421void 422printSystems() 423{ 424 System::printSystems(); 425} 426 427MasterID 428System::getMasterId(std::string master_name) 429{ 430 // strip off system name if the string starts with it 431 if (startswith(master_name, name())) 432 master_name = master_name.erase(0, name().size() + 1); 433 434 // CPUs in switch_cpus ask for ids again after switching 435 for (int i = 0; i < masterIds.size(); i++) { 436 if (masterIds[i] == master_name) { 437 return i; 438 } 439 } 440 441 // Verify that the statistics haven't been enabled yet 442 // Otherwise objects will have sized their stat buckets and 443 // they will be too small 444 445 if (Stats::enabled()) 446 fatal("Can't request a masterId after regStats(). \ 447 You must do so in init().\n"); 448 449 masterIds.push_back(master_name); 450 451 return masterIds.size() - 1; 452} 453 454std::string 455System::getMasterName(MasterID master_id) 456{ 457 if (master_id >= masterIds.size()) 458 fatal("Invalid master_id passed to getMasterName()\n"); 459 460 return masterIds[master_id]; 461} 462 463const char *System::MemoryModeStrings[4] = {"invalid", "atomic", "timing", 464 "atomic_noncaching"}; 465 466System * 467SystemParams::create() 468{ 469 return new System(this); 470} 471