system.cc revision 8703
1/* 2 * Copyright (c) 2011-2012 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 2003-2006 The Regents of The University of Michigan 15 * Copyright (c) 2011 Regents of the University of California 16 * All rights reserved. 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions are 20 * met: redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer; 22 * redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution; 25 * neither the name of the copyright holders nor the names of its 26 * contributors may be used to endorse or promote products derived from 27 * this software without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 * 41 * Authors: Steve Reinhardt 42 * Lisa Hsu 43 * Nathan Binkert 44 * Ali Saidi 45 * Rick Strong 46 */ 47 48#include "arch/isa_traits.hh" 49#include "arch/remote_gdb.hh" 50#include "arch/utility.hh" 51#include "base/loader/object_file.hh" 52#include "base/loader/symtab.hh" 53#include "base/trace.hh" 54#include "config/full_system.hh" 55#include "config/the_isa.hh" 56#include "cpu/thread_context.hh" 57#include "debug/Loader.hh" 58#include "debug/WorkItems.hh" 59#include "mem/mem_object.hh" 60#include "mem/physical.hh" 61#include "sim/byteswap.hh" 62#include "sim/debug.hh" 63#include "sim/system.hh" 64 65#if FULL_SYSTEM 66#include "arch/vtophys.hh" 67#include "kern/kernel_stats.hh" 68#include "mem/vport.hh" 69#else 70#include "params/System.hh" 71#endif 72 73using namespace std; 74using namespace TheISA; 75 76vector<System *> System::systemList; 77 78int System::numSystemsRunning = 0; 79 80System::System(Params *p) 81 : MemObject(p), _systemPort("system_port", this), 82 physmem(p->physmem), 83 _numContexts(0), 84#if FULL_SYSTEM 85 init_param(p->init_param), 86 loadAddrMask(p->load_addr_mask), 87#else 88 pagePtr(0), 89 nextPID(0), 90#endif 91 memoryMode(p->mem_mode), 92 workItemsBegin(0), 93 workItemsEnd(0), 94 numWorkIds(p->num_work_ids), 95 _params(p), 96 totalNumInsts(0), 97 instEventQueue("system instruction-based event queue") 98{ 99 // add self to global system list 100 systemList.push_back(this); 101 102 /** Keep track of all memories we can execute code out of 103 * in our system 104 */ 105 for (int x = 0; x < p->memories.size(); x++) { 106 if (!p->memories[x]) 107 continue; 108 memRanges.push_back(RangeSize(p->memories[x]->start(), 109 p->memories[x]->size())); 110 } 111 112#if FULL_SYSTEM 113 kernelSymtab = new SymbolTable; 114 if (!debugSymbolTable) 115 debugSymbolTable = new SymbolTable; 116 117 118 /** 119 * Get a functional port to memory 120 */ 121 Port *mem_port; 122 functionalPort = new FunctionalPort(name() + "-fport"); 123 mem_port = physmem->getPort("functional"); 124 functionalPort->setPeer(mem_port); 125 mem_port->setPeer(functionalPort); 126 127 virtPort = new VirtualPort(name() + "-fport"); 128 mem_port = physmem->getPort("functional"); 129 virtPort->setPeer(mem_port); 130 mem_port->setPeer(virtPort); 131 132 133 /** 134 * Load the kernel code into memory 135 */ 136 if (params()->kernel == "") { 137 inform("No kernel set for full system simulation. Assuming you know what" 138 " you're doing...\n"); 139 } else { 140 // Load kernel code 141 kernel = createObjectFile(params()->kernel); 142 inform("kernel located at: %s", params()->kernel); 143 144 if (kernel == NULL) 145 fatal("Could not load kernel file %s", params()->kernel); 146 147 // Load program sections into memory 148 kernel->loadSections(functionalPort, loadAddrMask); 149 150 // setup entry points 151 kernelStart = kernel->textBase(); 152 kernelEnd = kernel->bssBase() + kernel->bssSize(); 153 kernelEntry = kernel->entryPoint(); 154 155 // load symbols 156 if (!kernel->loadGlobalSymbols(kernelSymtab)) 157 fatal("could not load kernel symbols\n"); 158 159 if (!kernel->loadLocalSymbols(kernelSymtab)) 160 fatal("could not load kernel local symbols\n"); 161 162 if (!kernel->loadGlobalSymbols(debugSymbolTable)) 163 fatal("could not load kernel symbols\n"); 164 165 if (!kernel->loadLocalSymbols(debugSymbolTable)) 166 fatal("could not load kernel local symbols\n"); 167 168 DPRINTF(Loader, "Kernel start = %#x\n", kernelStart); 169 DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd); 170 DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry); 171 DPRINTF(Loader, "Kernel loaded...\n"); 172 } 173#endif // FULL_SYSTEM 174 175 // increment the number of running systms 176 numSystemsRunning++; 177 178 activeCpus.clear(); 179} 180 181System::~System() 182{ 183#if FULL_SYSTEM 184 delete kernelSymtab; 185 delete kernel; 186#else 187 panic("System::fixFuncEventAddr needs to be rewritten " 188 "to work with syscall emulation"); 189#endif // FULL_SYSTEM} 190 191 for (uint32_t j = 0; j < numWorkIds; j++) 192 delete workItemStats[j]; 193} 194 195Port* 196System::getPort(const std::string &if_name, int idx) 197{ 198 // no need to distinguish at the moment (besides checking) 199 return &_systemPort; 200} 201 202void 203System::setMemoryMode(Enums::MemoryMode mode) 204{ 205 assert(getState() == Drained); 206 memoryMode = mode; 207} 208 209bool System::breakpoint() 210{ 211 if (remoteGDB.size()) 212 return remoteGDB[0]->breakpoint(); 213 return false; 214} 215 216/** 217 * Setting rgdb_wait to a positive integer waits for a remote debugger to 218 * connect to that context ID before continuing. This should really 219 be a parameter on the CPU object or something... 220 */ 221int rgdb_wait = -1; 222 223int 224System::registerThreadContext(ThreadContext *tc, int assigned) 225{ 226 int id; 227 if (assigned == -1) { 228 for (id = 0; id < threadContexts.size(); id++) { 229 if (!threadContexts[id]) 230 break; 231 } 232 233 if (threadContexts.size() <= id) 234 threadContexts.resize(id + 1); 235 } else { 236 if (threadContexts.size() <= assigned) 237 threadContexts.resize(assigned + 1); 238 id = assigned; 239 } 240 241 if (threadContexts[id]) 242 fatal("Cannot have two CPUs with the same id (%d)\n", id); 243 244 threadContexts[id] = tc; 245 _numContexts++; 246 247 int port = getRemoteGDBPort(); 248 if (port) { 249 RemoteGDB *rgdb = new RemoteGDB(this, tc); 250 GDBListener *gdbl = new GDBListener(rgdb, port + id); 251 gdbl->listen(); 252 253 if (rgdb_wait != -1 && rgdb_wait == id) 254 gdbl->accept(); 255 256 if (remoteGDB.size() <= id) { 257 remoteGDB.resize(id + 1); 258 } 259 260 remoteGDB[id] = rgdb; 261 } 262 263 activeCpus.push_back(false); 264 265 return id; 266} 267 268int 269System::numRunningContexts() 270{ 271 int running = 0; 272 for (int i = 0; i < _numContexts; ++i) { 273 if (threadContexts[i]->status() != ThreadContext::Halted) 274 ++running; 275 } 276 return running; 277} 278 279void 280System::initState() 281{ 282#if FULL_SYSTEM 283 int i; 284 for (i = 0; i < threadContexts.size(); i++) 285 TheISA::startupCPU(threadContexts[i], i); 286#endif 287} 288 289void 290System::replaceThreadContext(ThreadContext *tc, int context_id) 291{ 292 if (context_id >= threadContexts.size()) { 293 panic("replaceThreadContext: bad id, %d >= %d\n", 294 context_id, threadContexts.size()); 295 } 296 297 threadContexts[context_id] = tc; 298 if (context_id < remoteGDB.size()) 299 remoteGDB[context_id]->replaceThreadContext(tc); 300} 301 302#if !FULL_SYSTEM 303Addr 304System::allocPhysPages(int npages) 305{ 306 Addr return_addr = pagePtr << LogVMPageSize; 307 pagePtr += npages; 308 if (return_addr >= physmem->size()) 309 fatal("Out of memory, please increase size of physical memory."); 310 return return_addr; 311} 312 313Addr 314System::memSize() 315{ 316 return physmem->size(); 317} 318 319Addr 320System::freeMemSize() 321{ 322 return physmem->size() - (pagePtr << LogVMPageSize); 323} 324 325#endif 326 327bool 328System::isMemory(const Addr addr) const 329{ 330 std::list<Range<Addr> >::const_iterator i; 331 for (i = memRanges.begin(); i != memRanges.end(); i++) { 332 if (*i == addr) 333 return true; 334 } 335 return false; 336} 337 338void 339System::resume() 340{ 341 SimObject::resume(); 342 totalNumInsts = 0; 343} 344 345void 346System::serialize(ostream &os) 347{ 348#if FULL_SYSTEM 349 kernelSymtab->serialize("kernel_symtab", os); 350#else // !FULL_SYSTEM 351 SERIALIZE_SCALAR(pagePtr); 352 SERIALIZE_SCALAR(nextPID); 353#endif 354} 355 356 357void 358System::unserialize(Checkpoint *cp, const string §ion) 359{ 360#if FULL_SYSTEM 361 kernelSymtab->unserialize("kernel_symtab", cp, section); 362#else // !FULL_SYSTEM 363 UNSERIALIZE_SCALAR(pagePtr); 364 UNSERIALIZE_SCALAR(nextPID); 365#endif 366} 367 368void 369System::regStats() 370{ 371 for (uint32_t j = 0; j < numWorkIds ; j++) { 372 workItemStats[j] = new Stats::Histogram(); 373 stringstream namestr; 374 ccprintf(namestr, "work_item_type%d", j); 375 workItemStats[j]->init(20) 376 .name(name() + "." + namestr.str()) 377 .desc("Run time stat for" + namestr.str()) 378 .prereq(*workItemStats[j]); 379 } 380} 381 382void 383System::workItemEnd(uint32_t tid, uint32_t workid) 384{ 385 std::pair<uint32_t,uint32_t> p(tid, workid); 386 if (!lastWorkItemStarted.count(p)) 387 return; 388 389 Tick samp = curTick() - lastWorkItemStarted[p]; 390 DPRINTF(WorkItems, "Work item end: %d\t%d\t%lld\n", tid, workid, samp); 391 392 if (workid >= numWorkIds) 393 fatal("Got workid greater than specified in system configuration\n"); 394 395 workItemStats[workid]->sample(samp); 396 lastWorkItemStarted.erase(p); 397} 398 399void 400System::printSystems() 401{ 402 vector<System *>::iterator i = systemList.begin(); 403 vector<System *>::iterator end = systemList.end(); 404 for (; i != end; ++i) { 405 System *sys = *i; 406 cerr << "System " << sys->name() << ": " << hex << sys << endl; 407 } 408} 409 410void 411printSystems() 412{ 413 System::printSystems(); 414} 415 416const char *System::MemoryModeStrings[3] = {"invalid", "atomic", 417 "timing"}; 418 419#if !FULL_SYSTEM 420 421System * 422SystemParams::create() 423{ 424 return new System(this); 425} 426 427#endif 428