system.cc revision 2378
1/*
2 * Copyright (c) 2002-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "base/loader/object_file.hh"
30#include "base/loader/symtab.hh"
31#include "cpu/exec_context.hh"
32#include "mem/functional/physical.hh"
33#include "sim/builder.hh"
34#include "sim/system.hh"
35#include "base/trace.hh"
36#if FULL_SYSTEM
37#include "base/remote_gdb.hh"
38#include "kern/kernel_stats.hh"
39#include "mem/functional/memory_control.hh"
40#include "targetarch/vtophys.hh"
41#endif
42
43using namespace std;
44
45vector<System *> System::systemList;
46
47int System::numSystemsRunning = 0;
48
49System::System(Params *p)
50    : SimObject(p->name), physmem(p->physmem), numcpus(0),
51#if FULL_SYSTEM
52      memctrl(p->memctrl), init_param(p->init_param),
53#else
54      page_ptr(0),
55#endif
56      params(p)
57{
58    // add self to global system list
59    systemList.push_back(this);
60
61#if FULL_SYSTEM
62    kernelSymtab = new SymbolTable;
63    consoleSymtab = new SymbolTable;
64    palSymtab = new SymbolTable;
65    debugSymbolTable = new SymbolTable;
66
67    /**
68     * Load the kernel, pal, and console code into memory
69     */
70    // Load kernel code
71    kernel = createObjectFile(params->kernel_path);
72    if (kernel == NULL)
73        fatal("Could not load kernel file %s", params->kernel_path);
74
75    // Load Console Code
76    console = createObjectFile(params->console_path);
77    if (console == NULL)
78        fatal("Could not load console file %s", params->console_path);
79
80    // Load pal file
81    pal = createObjectFile(params->palcode);
82    if (pal == NULL)
83        fatal("Could not load PALcode file %s", params->palcode);
84
85
86    // Load program sections into memory
87    pal->loadSections(physmem, true);
88    console->loadSections(physmem, true);
89    kernel->loadSections(physmem, true);
90
91    // setup entry points
92    kernelStart = kernel->textBase();
93    kernelEnd = kernel->bssBase() + kernel->bssSize();
94    kernelEntry = kernel->entryPoint();
95
96    // load symbols
97    if (!kernel->loadGlobalSymbols(kernelSymtab))
98        panic("could not load kernel symbols\n");
99
100    if (!kernel->loadLocalSymbols(kernelSymtab))
101        panic("could not load kernel local symbols\n");
102
103    if (!console->loadGlobalSymbols(consoleSymtab))
104        panic("could not load console symbols\n");
105
106    if (!pal->loadGlobalSymbols(palSymtab))
107        panic("could not load pal symbols\n");
108
109    if (!pal->loadLocalSymbols(palSymtab))
110        panic("could not load pal symbols\n");
111
112    if (!kernel->loadGlobalSymbols(debugSymbolTable))
113        panic("could not load kernel symbols\n");
114
115    if (!kernel->loadLocalSymbols(debugSymbolTable))
116        panic("could not load kernel local symbols\n");
117
118    if (!console->loadGlobalSymbols(debugSymbolTable))
119        panic("could not load console symbols\n");
120
121    if (!pal->loadGlobalSymbols(debugSymbolTable))
122        panic("could not load pal symbols\n");
123
124    if (!pal->loadLocalSymbols(debugSymbolTable))
125        panic("could not load pal symbols\n");
126
127
128    DPRINTF(Loader, "Kernel start = %#x\n", kernelStart);
129    DPRINTF(Loader, "Kernel end   = %#x\n", kernelEnd);
130    DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry);
131    DPRINTF(Loader, "Kernel loaded...\n");
132
133    Addr addr = 0;
134#ifdef DEBUG
135    consolePanicEvent = addConsoleFuncEvent<BreakPCEvent>("panic");
136#endif
137
138    /**
139     * Copy the osflags (kernel arguments) into the consoles
140     * memory. (Presently Linux does not use the console service
141     * routine to get these command line arguments, but Tru64 and
142     * others do.)
143     */
144    if (consoleSymtab->findAddress("env_booted_osflags", addr)) {
145        Addr paddr = vtophys(physmem, addr);
146        char *osflags = (char *)physmem->dma_addr(paddr, sizeof(uint32_t));
147
148        if (osflags)
149              strcpy(osflags, params->boot_osflags.c_str());
150    }
151
152    /**
153     * Set the hardware reset parameter block system type and revision
154     * information to Tsunami.
155     */
156    if (consoleSymtab->findAddress("m5_rpb", addr)) {
157        Addr paddr = vtophys(physmem, addr);
158        char *hwrpb = (char *)physmem->dma_addr(paddr, sizeof(uint64_t));
159
160        if (!hwrpb)
161            panic("could not translate hwrpb addr\n");
162
163        *(uint64_t*)(hwrpb+0x50) = htog(params->system_type);
164        *(uint64_t*)(hwrpb+0x58) = htog(params->system_rev);
165    } else
166        panic("could not find hwrpb\n");
167
168    kernelBinning = new Kernel::Binning(this);
169
170#endif // FULL_SYSTEM
171
172    // increment the number of running systms
173    numSystemsRunning++;
174}
175
176System::~System()
177{
178#if FULL_SYSTEM
179    delete kernelSymtab;
180    delete consoleSymtab;
181    delete kernel;
182    delete console;
183    delete pal;
184
185    delete kernelBinning;
186
187#ifdef DEBUG
188    delete consolePanicEvent;
189#endif
190
191#endif // FULL_SYSTEM
192}
193
194
195/**
196 * This function fixes up addresses that are used to match PCs for
197 * hooking simulator events on to target function executions.
198 *
199 * Alpha binaries may have multiple global offset table (GOT)
200 * sections.  A function that uses the GOT starts with a
201 * two-instruction prolog which sets the global pointer (gp == r29) to
202 * the appropriate GOT section.  The proper gp value is calculated
203 * based on the function address, which must be passed by the caller
204 * in the procedure value register (pv aka t12 == r27).  This sequence
205 * looks like the following:
206 *
207 *			opcode Ra Rb offset
208 *	ldah gp,X(pv)     09   29 27   X
209 *	lda  gp,Y(gp)     08   29 29   Y
210 *
211 * for some constant offsets X and Y.  The catch is that the linker
212 * (or maybe even the compiler, I'm not sure) may recognize that the
213 * caller and callee are using the same GOT section, making this
214 * prolog redundant, and modify the call target to skip these
215 * instructions.  If we check for execution of the first instruction
216 * of a function (the one the symbol points to) to detect when to skip
217 * it, we'll miss all these modified calls.  It might work to
218 * unconditionally check for the third instruction, but not all
219 * functions have this prolog, and there's some chance that those
220 * first two instructions could have undesired consequences.  So we do
221 * the Right Thing and pattern-match the first two instructions of the
222 * function to decide where to patch.
223 *
224 * Eventually this code should be moved into an ISA-specific file.
225 */
226Addr
227System::fixFuncEventAddr(Addr addr)
228{
229#if FULL_SYSTEM
230    // mask for just the opcode, Ra, and Rb fields (not the offset)
231    const uint32_t inst_mask = 0xffff0000;
232    // ldah gp,X(pv): opcode 9, Ra = 29, Rb = 27
233    const uint32_t gp_ldah_pattern = (9 << 26) | (29 << 21) | (27 << 16);
234    // lda  gp,Y(gp): opcode 8, Ra = 29, rb = 29
235    const uint32_t gp_lda_pattern  = (8 << 26) | (29 << 21) | (29 << 16);
236    // instruction size
237    const int sz = sizeof(uint32_t);
238
239    Addr paddr = vtophys(physmem, addr);
240    uint32_t i1 = *(uint32_t *)physmem->dma_addr(paddr, sz);
241    uint32_t i2 = *(uint32_t *)physmem->dma_addr(paddr+sz, sz);
242
243    if ((i1 & inst_mask) == gp_ldah_pattern &&
244        (i2 & inst_mask) == gp_lda_pattern) {
245        Addr new_addr = addr + 2*sz;
246        DPRINTF(Loader, "fixFuncEventAddr: %p -> %p", addr, new_addr);
247        return new_addr;
248    } else {
249        return addr;
250    }
251#else
252    panic("System::fixFuncEventAddr needs to be rewritten "
253          "to work with syscall emulation");
254#endif // FULL_SYSTEM}
255}
256
257#if FULL_SYSTEM
258void
259System::setAlphaAccess(Addr access)
260{
261    Addr addr = 0;
262    if (consoleSymtab->findAddress("m5AlphaAccess", addr)) {
263        Addr paddr = vtophys(physmem, addr);
264        uint64_t *m5AlphaAccess =
265            (uint64_t *)physmem->dma_addr(paddr, sizeof(uint64_t));
266
267        if (!m5AlphaAccess)
268            panic("could not translate m5AlphaAccess addr\n");
269
270        *m5AlphaAccess = htog(EV5::Phys2K0Seg(access));
271    } else
272        panic("could not find m5AlphaAccess\n");
273}
274
275
276bool
277System::breakpoint()
278{
279    return remoteGDB[0]->trap(ALPHA_KENTRY_INT);
280}
281
282int rgdb_wait = -1;
283
284#endif // FULL_SYSTEM
285
286int
287System::registerExecContext(ExecContext *xc, int id)
288{
289    if (id == -1) {
290        for (id = 0; id < execContexts.size(); id++) {
291            if (!execContexts[id])
292                break;
293        }
294    }
295
296    if (execContexts.size() <= id)
297        execContexts.resize(id + 1);
298
299    if (execContexts[id])
300        panic("Cannot have two CPUs with the same id (%d)\n", id);
301
302    execContexts[id] = xc;
303    numcpus++;
304
305#if FULL_SYSTEM
306    RemoteGDB *rgdb = new RemoteGDB(this, xc);
307    GDBListener *gdbl = new GDBListener(rgdb, 7000 + id);
308    gdbl->listen();
309    /**
310     * Uncommenting this line waits for a remote debugger to connect
311     * to the simulator before continuing.
312     */
313    if (rgdb_wait != -1 && rgdb_wait == id)
314        gdbl->accept();
315
316    if (remoteGDB.size() <= id) {
317        remoteGDB.resize(id + 1);
318    }
319
320    remoteGDB[id] = rgdb;
321#endif // FULL_SYSTEM
322
323    return id;
324}
325
326void
327System::startup()
328{
329    if (!execContexts.empty()) {
330        // activate with zero delay so that we start ticking right
331        // away on cycle 0
332        execContexts[0]->activate(0);
333    }
334}
335
336void
337System::replaceExecContext(ExecContext *xc, int id)
338{
339    if (id >= execContexts.size()) {
340        panic("replaceExecContext: bad id, %d >= %d\n",
341              id, execContexts.size());
342    }
343
344    execContexts[id] = xc;
345#if FULL_SYSTEM
346    remoteGDB[id]->replaceExecContext(xc);
347#endif // FULL_SYSTEM
348}
349
350#if !FULL_SYSTEM
351Addr
352System::new_page()
353{
354    Addr return_addr = page_ptr << LogVMPageSize;
355    ++page_ptr;
356    return return_addr;
357}
358#endif
359
360void
361System::regStats()
362{
363#if FULL_SYSTEM
364    kernelBinning->regStats(name() + ".kern");
365#endif // FULL_SYSTEM
366}
367
368void
369System::serialize(ostream &os)
370{
371#if FULL_SYSTEM
372    kernelBinning->serialize(os);
373
374    kernelSymtab->serialize("kernel_symtab", os);
375    consoleSymtab->serialize("console_symtab", os);
376    palSymtab->serialize("pal_symtab", os);
377#endif // FULL_SYSTEM
378}
379
380
381void
382System::unserialize(Checkpoint *cp, const string &section)
383{
384#if FULL_SYSTEM
385    kernelBinning->unserialize(cp, section);
386
387    kernelSymtab->unserialize("kernel_symtab", cp, section);
388    consoleSymtab->unserialize("console_symtab", cp, section);
389    palSymtab->unserialize("pal_symtab", cp, section);
390#endif // FULL_SYSTEM
391}
392
393void
394System::printSystems()
395{
396    vector<System *>::iterator i = systemList.begin();
397    vector<System *>::iterator end = systemList.end();
398    for (; i != end; ++i) {
399        System *sys = *i;
400        cerr << "System " << sys->name() << ": " << hex << sys << endl;
401    }
402}
403
404extern "C"
405void
406printSystems()
407{
408    System::printSystems();
409}
410
411BEGIN_DECLARE_SIM_OBJECT_PARAMS(System)
412
413    SimObjectParam<PhysicalMemory *> physmem;
414
415#if FULL_SYSTEM
416    Param<Tick> boot_cpu_frequency;
417    SimObjectParam<MemoryController *> memctrl;
418
419    Param<string> kernel;
420    Param<string> console;
421    Param<string> pal;
422
423    Param<string> boot_osflags;
424    Param<string> readfile;
425    Param<unsigned int> init_param;
426
427    Param<uint64_t> system_type;
428    Param<uint64_t> system_rev;
429
430    Param<bool> bin;
431    VectorParam<string> binned_fns;
432    Param<bool> bin_int;
433#endif // FULL_SYSTEM
434
435END_DECLARE_SIM_OBJECT_PARAMS(System)
436
437BEGIN_INIT_SIM_OBJECT_PARAMS(System)
438
439    INIT_PARAM(physmem, "physical memory")
440
441#if FULL_SYSTEM
442    ,
443    INIT_PARAM(boot_cpu_frequency, "Frequency of the boot CPU"),
444    INIT_PARAM(memctrl, "memory controller"),
445    INIT_PARAM(kernel, "file that contains the kernel code"),
446    INIT_PARAM(console, "file that contains the console code"),
447    INIT_PARAM(pal, "file that contains palcode"),
448    INIT_PARAM_DFLT(boot_osflags, "flags to pass to the kernel during boot",
449                    "a"),
450    INIT_PARAM_DFLT(readfile, "file to read startup script from", ""),
451    INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0),
452    INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34),
453    INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10),
454    INIT_PARAM_DFLT(bin, "is this system to be binned", false),
455    INIT_PARAM(binned_fns, "functions to be broken down and binned"),
456    INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", true)
457#endif // FULL_SYSTEM
458
459END_INIT_SIM_OBJECT_PARAMS(System)
460
461CREATE_SIM_OBJECT(System)
462{
463    System::Params *p = new System::Params;
464    p->name = getInstanceName();
465    p->physmem = physmem;
466#if FULL_SYSTEM
467    p->boot_cpu_frequency = boot_cpu_frequency;
468    p->memctrl = memctrl;
469    p->kernel_path = kernel;
470    p->console_path = console;
471    p->palcode = pal;
472    p->boot_osflags = boot_osflags;
473    p->init_param = init_param;
474    p->readfile = readfile;
475    p->system_type = system_type;
476    p->system_rev = system_rev;
477    p->bin = bin;
478    p->binned_fns = binned_fns;
479    p->bin_int = bin_int;
480#endif // FULL_SYSTEM
481    return new System(p);
482}
483
484REGISTER_SIM_OBJECT("System", System)
485
486