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 &section)
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