system.cc revision 9007
113521Sgabeblack@google.com/* 213521Sgabeblack@google.com * Copyright (c) 2011-2012 ARM Limited 313521Sgabeblack@google.com * All rights reserved 413521Sgabeblack@google.com * 513521Sgabeblack@google.com * The license below extends only to copyright in the software and shall 613521Sgabeblack@google.com * not be construed as granting a license to any other intellectual 713521Sgabeblack@google.com * property including but not limited to intellectual property relating 813521Sgabeblack@google.com * to a hardware implementation of the functionality of the software 913521Sgabeblack@google.com * licensed hereunder. You may use the software subject to the license 1013521Sgabeblack@google.com * terms below provided that you ensure that this notice is replicated 1113521Sgabeblack@google.com * unmodified and in its entirety in all distributions of the software, 1213521Sgabeblack@google.com * modified or unmodified, in source code or in binary form. 1313521Sgabeblack@google.com * 1413521Sgabeblack@google.com * Copyright (c) 2003-2006 The Regents of The University of Michigan 1513521Sgabeblack@google.com * Copyright (c) 2011 Regents of the University of California 1613521Sgabeblack@google.com * All rights reserved. 1713521Sgabeblack@google.com * 1813521Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without 1913521Sgabeblack@google.com * modification, are permitted provided that the following conditions are 2013521Sgabeblack@google.com * met: redistributions of source code must retain the above copyright 2113521Sgabeblack@google.com * notice, this list of conditions and the following disclaimer; 2213521Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright 2313521Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the 2413521Sgabeblack@google.com * documentation and/or other materials provided with the distribution; 2513521Sgabeblack@google.com * neither the name of the copyright holders nor the names of its 2613521Sgabeblack@google.com * contributors may be used to endorse or promote products derived from 2713521Sgabeblack@google.com * this software without specific prior written permission. 2813521Sgabeblack@google.com * 2913521Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3013521Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3113521Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3213521Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3313521Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3413521Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3513521Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3613521Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3713521Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3813521Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3913521Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 4013521Sgabeblack@google.com * 4113521Sgabeblack@google.com * Authors: Steve Reinhardt 4213521Sgabeblack@google.com * Lisa Hsu 4313521Sgabeblack@google.com * Nathan Binkert 4413521Sgabeblack@google.com * Ali Saidi 4513521Sgabeblack@google.com * Rick Strong 4613521Sgabeblack@google.com */ 4713521Sgabeblack@google.com 4813521Sgabeblack@google.com#include "arch/isa_traits.hh" 4913521Sgabeblack@google.com#include "arch/remote_gdb.hh" 5013521Sgabeblack@google.com#include "arch/utility.hh" 5113521Sgabeblack@google.com#include "arch/vtophys.hh" 5213521Sgabeblack@google.com#include "base/loader/object_file.hh" 5313521Sgabeblack@google.com#include "base/loader/symtab.hh" 5413521Sgabeblack@google.com#include "base/trace.hh" 5513521Sgabeblack@google.com#include "config/the_isa.hh" 5613521Sgabeblack@google.com#include "cpu/thread_context.hh" 5713521Sgabeblack@google.com#include "debug/Loader.hh" 5813521Sgabeblack@google.com#include "debug/WorkItems.hh" 5913521Sgabeblack@google.com#include "kern/kernel_stats.hh" 6013521Sgabeblack@google.com#include "mem/physical.hh" 6113521Sgabeblack@google.com#include "params/System.hh" 6213521Sgabeblack@google.com#include "sim/byteswap.hh" 6313521Sgabeblack@google.com#include "sim/debug.hh" 6413521Sgabeblack@google.com#include "sim/full_system.hh" 6513521Sgabeblack@google.com#include "sim/system.hh" 6613521Sgabeblack@google.com 6713521Sgabeblack@google.comusing namespace std; 6813521Sgabeblack@google.comusing namespace TheISA; 6913521Sgabeblack@google.com 7013521Sgabeblack@google.comvector<System *> System::systemList; 7113521Sgabeblack@google.com 7213521Sgabeblack@google.comint System::numSystemsRunning = 0; 7313521Sgabeblack@google.com 7413521Sgabeblack@google.comSystem::System(Params *p) 7513521Sgabeblack@google.com : MemObject(p), _systemPort("system_port", this), 7613521Sgabeblack@google.com _numContexts(0), 7713521Sgabeblack@google.com pagePtr(0), 7813521Sgabeblack@google.com init_param(p->init_param), 7913521Sgabeblack@google.com physProxy(_systemPort), 8013521Sgabeblack@google.com virtProxy(_systemPort), 8113521Sgabeblack@google.com loadAddrMask(p->load_addr_mask), 8213521Sgabeblack@google.com nextPID(0), 8313521Sgabeblack@google.com physmem(p->memories), 8413521Sgabeblack@google.com memoryMode(p->mem_mode), 8513521Sgabeblack@google.com workItemsBegin(0), 8613521Sgabeblack@google.com workItemsEnd(0), 8713521Sgabeblack@google.com numWorkIds(p->num_work_ids), 8813521Sgabeblack@google.com _params(p), 8913521Sgabeblack@google.com totalNumInsts(0), 9013521Sgabeblack@google.com instEventQueue("system instruction-based event queue") 9113521Sgabeblack@google.com{ 9213521Sgabeblack@google.com // add self to global system list 9313521Sgabeblack@google.com systemList.push_back(this); 9413521Sgabeblack@google.com 9513521Sgabeblack@google.com if (FullSystem) { 9613521Sgabeblack@google.com kernelSymtab = new SymbolTable; 9713521Sgabeblack@google.com if (!debugSymbolTable) 9813521Sgabeblack@google.com debugSymbolTable = new SymbolTable; 9913521Sgabeblack@google.com } 10013521Sgabeblack@google.com 10113521Sgabeblack@google.com // Get the generic system master IDs 10213521Sgabeblack@google.com MasterID tmp_id M5_VAR_USED; 10313521Sgabeblack@google.com tmp_id = getMasterId("writebacks"); 10413521Sgabeblack@google.com assert(tmp_id == Request::wbMasterId); 10513521Sgabeblack@google.com tmp_id = getMasterId("functional"); 10613521Sgabeblack@google.com assert(tmp_id == Request::funcMasterId); 10713521Sgabeblack@google.com tmp_id = getMasterId("interrupt"); 10813521Sgabeblack@google.com assert(tmp_id == Request::intMasterId); 10913521Sgabeblack@google.com 11013521Sgabeblack@google.com if (FullSystem) { 11113521Sgabeblack@google.com if (params()->kernel == "") { 11213521Sgabeblack@google.com inform("No kernel set for full system simulation. " 11313521Sgabeblack@google.com "Assuming you know what you're doing if not SPARC ISA\n"); 11413521Sgabeblack@google.com } else { 11513521Sgabeblack@google.com // Get the kernel code 11613521Sgabeblack@google.com kernel = createObjectFile(params()->kernel); 11713521Sgabeblack@google.com inform("kernel located at: %s", params()->kernel); 11813521Sgabeblack@google.com 11913521Sgabeblack@google.com if (kernel == NULL) 12013521Sgabeblack@google.com fatal("Could not load kernel file %s", params()->kernel); 12113521Sgabeblack@google.com 12213521Sgabeblack@google.com // setup entry points 12313521Sgabeblack@google.com kernelStart = kernel->textBase(); 12413521Sgabeblack@google.com kernelEnd = kernel->bssBase() + kernel->bssSize(); 12513521Sgabeblack@google.com kernelEntry = kernel->entryPoint(); 12613521Sgabeblack@google.com 12713521Sgabeblack@google.com // load symbols 12813521Sgabeblack@google.com if (!kernel->loadGlobalSymbols(kernelSymtab)) 12913521Sgabeblack@google.com fatal("could not load kernel symbols\n"); 13013521Sgabeblack@google.com 13113521Sgabeblack@google.com if (!kernel->loadLocalSymbols(kernelSymtab)) 13213521Sgabeblack@google.com fatal("could not load kernel local symbols\n"); 13313521Sgabeblack@google.com 13413521Sgabeblack@google.com if (!kernel->loadGlobalSymbols(debugSymbolTable)) 13513521Sgabeblack@google.com fatal("could not load kernel symbols\n"); 13613521Sgabeblack@google.com 13713521Sgabeblack@google.com if (!kernel->loadLocalSymbols(debugSymbolTable)) 13813521Sgabeblack@google.com fatal("could not load kernel local symbols\n"); 13913521Sgabeblack@google.com 14013521Sgabeblack@google.com // Loading only needs to happen once and after memory system is 14113521Sgabeblack@google.com // connected so it will happen in initState() 14213521Sgabeblack@google.com } 14313521Sgabeblack@google.com } 14413521Sgabeblack@google.com 14513521Sgabeblack@google.com // increment the number of running systms 14613521Sgabeblack@google.com numSystemsRunning++; 14713521Sgabeblack@google.com 14813521Sgabeblack@google.com} 14913521Sgabeblack@google.com 15013521Sgabeblack@google.comSystem::~System() 15113521Sgabeblack@google.com{ 15213521Sgabeblack@google.com delete kernelSymtab; 15313521Sgabeblack@google.com delete kernel; 15413521Sgabeblack@google.com 15513521Sgabeblack@google.com for (uint32_t j = 0; j < numWorkIds; j++) 15613521Sgabeblack@google.com delete workItemStats[j]; 15713521Sgabeblack@google.com} 15813521Sgabeblack@google.com 15913521Sgabeblack@google.comvoid 16013521Sgabeblack@google.comSystem::init() 16113521Sgabeblack@google.com{ 16213521Sgabeblack@google.com // check that the system port is connected 16313521Sgabeblack@google.com if (!_systemPort.isConnected()) 16413521Sgabeblack@google.com panic("System port on %s is not connected.\n", name()); 16513521Sgabeblack@google.com} 16613521Sgabeblack@google.com 16713521Sgabeblack@google.comMasterPort& 16813521Sgabeblack@google.comSystem::getMasterPort(const std::string &if_name, int idx) 16913521Sgabeblack@google.com{ 17013521Sgabeblack@google.com // no need to distinguish at the moment (besides checking) 17113521Sgabeblack@google.com return _systemPort; 17213521Sgabeblack@google.com} 17313521Sgabeblack@google.com 17413521Sgabeblack@google.comvoid 17513521Sgabeblack@google.comSystem::setMemoryMode(Enums::MemoryMode mode) 17613521Sgabeblack@google.com{ 17713521Sgabeblack@google.com assert(getState() == Drained); 17813521Sgabeblack@google.com memoryMode = mode; 17913521Sgabeblack@google.com} 18013521Sgabeblack@google.com 18113521Sgabeblack@google.combool System::breakpoint() 18213521Sgabeblack@google.com{ 18313521Sgabeblack@google.com if (remoteGDB.size()) 18413521Sgabeblack@google.com return remoteGDB[0]->breakpoint(); 18513521Sgabeblack@google.com return false; 18613521Sgabeblack@google.com} 18713521Sgabeblack@google.com 18813521Sgabeblack@google.com/** 18913521Sgabeblack@google.com * Setting rgdb_wait to a positive integer waits for a remote debugger to 19013521Sgabeblack@google.com * connect to that context ID before continuing. This should really 19113521Sgabeblack@google.com be a parameter on the CPU object or something... 19213521Sgabeblack@google.com */ 19313521Sgabeblack@google.comint rgdb_wait = -1; 19413521Sgabeblack@google.com 19513521Sgabeblack@google.comint 19613521Sgabeblack@google.comSystem::registerThreadContext(ThreadContext *tc, int assigned) 19713521Sgabeblack@google.com{ 19813521Sgabeblack@google.com int id; 19913521Sgabeblack@google.com if (assigned == -1) { 20013521Sgabeblack@google.com for (id = 0; id < threadContexts.size(); id++) { 20113521Sgabeblack@google.com if (!threadContexts[id]) 20213521Sgabeblack@google.com break; 20313521Sgabeblack@google.com } 20413521Sgabeblack@google.com 20513521Sgabeblack@google.com if (threadContexts.size() <= id) 20613521Sgabeblack@google.com threadContexts.resize(id + 1); 20713521Sgabeblack@google.com } else { 20813521Sgabeblack@google.com if (threadContexts.size() <= assigned) 20913521Sgabeblack@google.com threadContexts.resize(assigned + 1); 21013521Sgabeblack@google.com id = assigned; 21113521Sgabeblack@google.com } 21213521Sgabeblack@google.com 21313521Sgabeblack@google.com if (threadContexts[id]) 21413521Sgabeblack@google.com fatal("Cannot have two CPUs with the same id (%d)\n", id); 21513521Sgabeblack@google.com 21613521Sgabeblack@google.com threadContexts[id] = tc; 21713521Sgabeblack@google.com _numContexts++; 21813521Sgabeblack@google.com 21913521Sgabeblack@google.com int port = getRemoteGDBPort(); 22013521Sgabeblack@google.com if (port) { 22113521Sgabeblack@google.com RemoteGDB *rgdb = new RemoteGDB(this, tc); 22213521Sgabeblack@google.com GDBListener *gdbl = new GDBListener(rgdb, port + id); 22313521Sgabeblack@google.com gdbl->listen(); 224 225 if (rgdb_wait != -1 && rgdb_wait == id) 226 gdbl->accept(); 227 228 if (remoteGDB.size() <= id) { 229 remoteGDB.resize(id + 1); 230 } 231 232 remoteGDB[id] = rgdb; 233 } 234 235 activeCpus.push_back(false); 236 237 return id; 238} 239 240int 241System::numRunningContexts() 242{ 243 int running = 0; 244 for (int i = 0; i < _numContexts; ++i) { 245 if (threadContexts[i]->status() != ThreadContext::Halted) 246 ++running; 247 } 248 return running; 249} 250 251void 252System::initState() 253{ 254 int i; 255 if (FullSystem) { 256 for (i = 0; i < threadContexts.size(); i++) 257 TheISA::startupCPU(threadContexts[i], i); 258 // Moved from the constructor to here since it relies on the 259 // address map being resolved in the interconnect 260 /** 261 * Load the kernel code into memory 262 */ 263 if (params()->kernel != "") { 264 // Load program sections into memory 265 kernel->loadSections(physProxy, loadAddrMask); 266 267 DPRINTF(Loader, "Kernel start = %#x\n", kernelStart); 268 DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd); 269 DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry); 270 DPRINTF(Loader, "Kernel loaded...\n"); 271 } 272 } 273 274 activeCpus.clear(); 275 276 if (!FullSystem) 277 return; 278 279 for (i = 0; i < threadContexts.size(); i++) 280 TheISA::startupCPU(threadContexts[i], i); 281} 282 283void 284System::replaceThreadContext(ThreadContext *tc, int context_id) 285{ 286 if (context_id >= threadContexts.size()) { 287 panic("replaceThreadContext: bad id, %d >= %d\n", 288 context_id, threadContexts.size()); 289 } 290 291 threadContexts[context_id] = tc; 292 if (context_id < remoteGDB.size()) 293 remoteGDB[context_id]->replaceThreadContext(tc); 294} 295 296Addr 297System::allocPhysPages(int npages) 298{ 299 Addr return_addr = pagePtr << LogVMPageSize; 300 pagePtr += npages; 301 if ((pagePtr << LogVMPageSize) > physmem.totalSize()) 302 fatal("Out of memory, please increase size of physical memory."); 303 return return_addr; 304} 305 306Addr 307System::memSize() const 308{ 309 return physmem.totalSize(); 310} 311 312Addr 313System::freeMemSize() const 314{ 315 return physmem.totalSize() - (pagePtr << LogVMPageSize); 316} 317 318bool 319System::isMemAddr(Addr addr) const 320{ 321 return physmem.isMemAddr(addr); 322} 323 324void 325System::resume() 326{ 327 SimObject::resume(); 328 totalNumInsts = 0; 329} 330 331void 332System::serialize(ostream &os) 333{ 334 if (FullSystem) 335 kernelSymtab->serialize("kernel_symtab", os); 336 SERIALIZE_SCALAR(pagePtr); 337 SERIALIZE_SCALAR(nextPID); 338} 339 340 341void 342System::unserialize(Checkpoint *cp, const string §ion) 343{ 344 if (FullSystem) 345 kernelSymtab->unserialize("kernel_symtab", cp, section); 346 UNSERIALIZE_SCALAR(pagePtr); 347 UNSERIALIZE_SCALAR(nextPID); 348} 349 350void 351System::regStats() 352{ 353 for (uint32_t j = 0; j < numWorkIds ; j++) { 354 workItemStats[j] = new Stats::Histogram(); 355 stringstream namestr; 356 ccprintf(namestr, "work_item_type%d", j); 357 workItemStats[j]->init(20) 358 .name(name() + "." + namestr.str()) 359 .desc("Run time stat for" + namestr.str()) 360 .prereq(*workItemStats[j]); 361 } 362} 363 364void 365System::workItemEnd(uint32_t tid, uint32_t workid) 366{ 367 std::pair<uint32_t,uint32_t> p(tid, workid); 368 if (!lastWorkItemStarted.count(p)) 369 return; 370 371 Tick samp = curTick() - lastWorkItemStarted[p]; 372 DPRINTF(WorkItems, "Work item end: %d\t%d\t%lld\n", tid, workid, samp); 373 374 if (workid >= numWorkIds) 375 fatal("Got workid greater than specified in system configuration\n"); 376 377 workItemStats[workid]->sample(samp); 378 lastWorkItemStarted.erase(p); 379} 380 381void 382System::printSystems() 383{ 384 vector<System *>::iterator i = systemList.begin(); 385 vector<System *>::iterator end = systemList.end(); 386 for (; i != end; ++i) { 387 System *sys = *i; 388 cerr << "System " << sys->name() << ": " << hex << sys << endl; 389 } 390} 391 392void 393printSystems() 394{ 395 System::printSystems(); 396} 397 398MasterID 399System::getMasterId(std::string master_name) 400{ 401 // strip off system name if the string starts with it 402 if (master_name.size() > name().size() && 403 master_name.compare(0, name().size(), name()) == 0) 404 master_name = master_name.erase(0, name().size() + 1); 405 406 // CPUs in switch_cpus ask for ids again after switching 407 for (int i = 0; i < masterIds.size(); i++) { 408 if (masterIds[i] == master_name) { 409 return i; 410 } 411 } 412 413 // Verify that the statistics haven't been enabled yet 414 // Otherwise objects will have sized their stat buckets and 415 // they will be too small 416 417 if (Stats::enabled()) 418 fatal("Can't request a masterId after regStats(). \ 419 You must do so in init().\n"); 420 421 masterIds.push_back(master_name); 422 423 return masterIds.size() - 1; 424} 425 426std::string 427System::getMasterName(MasterID master_id) 428{ 429 if (master_id >= masterIds.size()) 430 fatal("Invalid master_id passed to getMasterName()\n"); 431 432 return masterIds[master_id]; 433} 434 435const char *System::MemoryModeStrings[3] = {"invalid", "atomic", 436 "timing"}; 437 438System * 439SystemParams::create() 440{ 441 return new System(this); 442} 443