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