system.cc revision 8826:6cc162805986
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 "arch/vtophys.hh"
52#include "base/loader/object_file.hh"
53#include "base/loader/symtab.hh"
54#include "base/trace.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 "kern/kernel_stats.hh"
60#include "mem/fs_translating_port_proxy.hh"
61#include "mem/mem_object.hh"
62#include "mem/physical.hh"
63#include "params/System.hh"
64#include "sim/byteswap.hh"
65#include "sim/debug.hh"
66#include "sim/full_system.hh"
67#include "sim/system.hh"
68
69using namespace std;
70using namespace TheISA;
71
72vector<System *> System::systemList;
73
74int System::numSystemsRunning = 0;
75
76System::System(Params *p)
77    : MemObject(p), _systemPort("system_port", this),
78      physmem(p->physmem),
79      _numContexts(0),
80      pagePtr(0),
81      init_param(p->init_param),
82      loadAddrMask(p->load_addr_mask),
83      nextPID(0),
84      memoryMode(p->mem_mode),
85      workItemsBegin(0),
86      workItemsEnd(0),
87      numWorkIds(p->num_work_ids),
88      _params(p),
89      totalNumInsts(0),
90      instEventQueue("system instruction-based event queue")
91{
92    // add self to global system list
93    systemList.push_back(this);
94
95    /** Keep track of all memories we can execute code out of
96     * in our system
97     */
98    for (int x = 0; x < p->memories.size(); x++) {
99        if (!p->memories[x])
100            continue;
101        memRanges.push_back(RangeSize(p->memories[x]->start(),
102                                      p->memories[x]->size()));
103    }
104
105    if (FullSystem) {
106        kernelSymtab = new SymbolTable;
107        if (!debugSymbolTable)
108            debugSymbolTable = new SymbolTable;
109
110        /**
111         * Get a port proxy to memory
112         */
113        physProxy = new PortProxy(*getSystemPort());
114        virtProxy = new FSTranslatingPortProxy(*getSystemPort());
115    }
116}
117
118System::~System()
119{
120    delete kernelSymtab;
121    delete kernel;
122
123    for (uint32_t j = 0; j < numWorkIds; j++)
124        delete workItemStats[j];
125}
126
127void
128System::init()
129{
130    // check that the system port is connected
131    if (!_systemPort.isConnected())
132        panic("System port on %s is not connected.\n", name());
133}
134
135Port*
136System::getPort(const std::string &if_name, int idx)
137{
138    // no need to distinguish at the moment (besides checking)
139    return &_systemPort;
140}
141
142void
143System::setMemoryMode(Enums::MemoryMode mode)
144{
145    assert(getState() == Drained);
146    memoryMode = mode;
147}
148
149bool System::breakpoint()
150{
151    if (remoteGDB.size())
152        return remoteGDB[0]->breakpoint();
153    return false;
154}
155
156/**
157 * Setting rgdb_wait to a positive integer waits for a remote debugger to
158 * connect to that context ID before continuing.  This should really
159   be a parameter on the CPU object or something...
160 */
161int rgdb_wait = -1;
162
163int
164System::registerThreadContext(ThreadContext *tc, int assigned)
165{
166    int id;
167    if (assigned == -1) {
168        for (id = 0; id < threadContexts.size(); id++) {
169            if (!threadContexts[id])
170                break;
171        }
172
173        if (threadContexts.size() <= id)
174            threadContexts.resize(id + 1);
175    } else {
176        if (threadContexts.size() <= assigned)
177            threadContexts.resize(assigned + 1);
178        id = assigned;
179    }
180
181    if (threadContexts[id])
182        fatal("Cannot have two CPUs with the same id (%d)\n", id);
183
184    threadContexts[id] = tc;
185    _numContexts++;
186
187    int port = getRemoteGDBPort();
188    if (port) {
189        RemoteGDB *rgdb = new RemoteGDB(this, tc);
190        GDBListener *gdbl = new GDBListener(rgdb, port + id);
191        gdbl->listen();
192
193        if (rgdb_wait != -1 && rgdb_wait == id)
194            gdbl->accept();
195
196        if (remoteGDB.size() <= id) {
197            remoteGDB.resize(id + 1);
198        }
199
200        remoteGDB[id] = rgdb;
201    }
202
203    activeCpus.push_back(false);
204
205    return id;
206}
207
208int
209System::numRunningContexts()
210{
211    int running = 0;
212    for (int i = 0; i < _numContexts; ++i) {
213        if (threadContexts[i]->status() != ThreadContext::Halted)
214            ++running;
215    }
216    return running;
217}
218
219void
220System::initState()
221{
222    int i;
223    if (FullSystem) {
224        for (i = 0; i < threadContexts.size(); i++)
225            TheISA::startupCPU(threadContexts[i], i);
226        // Moved from the constructor to here since it relies on the
227        // address map being resolved in the interconnect
228        /**
229         * Load the kernel code into memory
230         */
231        if (params()->kernel == "") {
232            inform("No kernel set for full system simulation. "
233                    "Assuming you know what you're doing...\n");
234        } else {
235            // Load kernel code
236            kernel = createObjectFile(params()->kernel);
237            inform("kernel located at: %s", params()->kernel);
238
239            if (kernel == NULL)
240                fatal("Could not load kernel file %s", params()->kernel);
241
242            // Load program sections into memory
243            kernel->loadSections(physProxy, loadAddrMask);
244
245            // setup entry points
246            kernelStart = kernel->textBase();
247            kernelEnd = kernel->bssBase() + kernel->bssSize();
248            kernelEntry = kernel->entryPoint();
249
250            // load symbols
251            if (!kernel->loadGlobalSymbols(kernelSymtab))
252                fatal("could not load kernel symbols\n");
253
254            if (!kernel->loadLocalSymbols(kernelSymtab))
255                fatal("could not load kernel local symbols\n");
256
257            if (!kernel->loadGlobalSymbols(debugSymbolTable))
258                fatal("could not load kernel symbols\n");
259
260            if (!kernel->loadLocalSymbols(debugSymbolTable))
261                fatal("could not load kernel local symbols\n");
262
263            DPRINTF(Loader, "Kernel start = %#x\n", kernelStart);
264            DPRINTF(Loader, "Kernel end   = %#x\n", kernelEnd);
265            DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry);
266            DPRINTF(Loader, "Kernel loaded...\n");
267        }
268    }
269
270    // increment the number of running systms
271    numSystemsRunning++;
272
273    activeCpus.clear();
274
275    if (!FullSystem)
276        return;
277
278    for (i = 0; i < threadContexts.size(); i++)
279        TheISA::startupCPU(threadContexts[i], i);
280}
281
282void
283System::replaceThreadContext(ThreadContext *tc, int context_id)
284{
285    if (context_id >= threadContexts.size()) {
286        panic("replaceThreadContext: bad id, %d >= %d\n",
287              context_id, threadContexts.size());
288    }
289
290    threadContexts[context_id] = tc;
291    if (context_id < remoteGDB.size())
292        remoteGDB[context_id]->replaceThreadContext(tc);
293}
294
295Addr
296System::allocPhysPages(int npages)
297{
298    Addr return_addr = pagePtr << LogVMPageSize;
299    pagePtr += npages;
300    if (pagePtr > physmem->size())
301        fatal("Out of memory, please increase size of physical memory.");
302    return return_addr;
303}
304
305Addr
306System::memSize()
307{
308    return physmem->size();
309}
310
311Addr
312System::freeMemSize()
313{
314   return physmem->size() - (pagePtr << LogVMPageSize);
315}
316
317bool
318System::isMemory(const Addr addr) const
319{
320    std::list<Range<Addr> >::const_iterator i;
321    for (i = memRanges.begin(); i != memRanges.end(); i++) {
322        if (*i == addr)
323            return true;
324    }
325    return false;
326}
327
328void
329System::resume()
330{
331    SimObject::resume();
332    totalNumInsts = 0;
333}
334
335void
336System::serialize(ostream &os)
337{
338    if (FullSystem)
339        kernelSymtab->serialize("kernel_symtab", os);
340    SERIALIZE_SCALAR(pagePtr);
341    SERIALIZE_SCALAR(nextPID);
342}
343
344
345void
346System::unserialize(Checkpoint *cp, const string &section)
347{
348    if (FullSystem)
349        kernelSymtab->unserialize("kernel_symtab", cp, section);
350    UNSERIALIZE_SCALAR(pagePtr);
351    UNSERIALIZE_SCALAR(nextPID);
352}
353
354void
355System::regStats()
356{
357    for (uint32_t j = 0; j < numWorkIds ; j++) {
358        workItemStats[j] = new Stats::Histogram();
359        stringstream namestr;
360        ccprintf(namestr, "work_item_type%d", j);
361        workItemStats[j]->init(20)
362                         .name(name() + "." + namestr.str())
363                         .desc("Run time stat for" + namestr.str())
364                         .prereq(*workItemStats[j]);
365    }
366}
367
368void
369System::workItemEnd(uint32_t tid, uint32_t workid)
370{
371    std::pair<uint32_t,uint32_t> p(tid, workid);
372    if (!lastWorkItemStarted.count(p))
373        return;
374
375    Tick samp = curTick() - lastWorkItemStarted[p];
376    DPRINTF(WorkItems, "Work item end: %d\t%d\t%lld\n", tid, workid, samp);
377
378    if (workid >= numWorkIds)
379        fatal("Got workid greater than specified in system configuration\n");
380
381    workItemStats[workid]->sample(samp);
382    lastWorkItemStarted.erase(p);
383}
384
385void
386System::printSystems()
387{
388    vector<System *>::iterator i = systemList.begin();
389    vector<System *>::iterator end = systemList.end();
390    for (; i != end; ++i) {
391        System *sys = *i;
392        cerr << "System " << sys->name() << ": " << hex << sys << endl;
393    }
394}
395
396void
397printSystems()
398{
399    System::printSystems();
400}
401
402const char *System::MemoryModeStrings[3] = {"invalid", "atomic",
403    "timing"};
404
405System *
406SystemParams::create()
407{
408    return new System(this);
409}
410