mem: Dynamically determine page bytes in memory components
[gem5.git] / src / sim / system.cc
1 /*
2 * Copyright (c) 2011-2014 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/remote_gdb.hh"
49 #include "arch/utility.hh"
50 #include "base/loader/object_file.hh"
51 #include "base/loader/symtab.hh"
52 #include "base/str.hh"
53 #include "base/trace.hh"
54 #include "cpu/thread_context.hh"
55 #include "debug/Loader.hh"
56 #include "debug/WorkItems.hh"
57 #include "kern/kernel_stats.hh"
58 #include "mem/abstract_mem.hh"
59 #include "mem/physical.hh"
60 #include "params/System.hh"
61 #include "sim/byteswap.hh"
62 #include "sim/debug.hh"
63 #include "sim/full_system.hh"
64 #include "sim/system.hh"
65
66 using namespace std;
67 using namespace TheISA;
68
69 vector<System *> System::systemList;
70
71 int System::numSystemsRunning = 0;
72
73 System::System(Params *p)
74 : MemObject(p), _systemPort("system_port", this),
75 _numContexts(0),
76 pagePtr(0),
77 init_param(p->init_param),
78 physProxy(_systemPort, p->cache_line_size),
79 kernelSymtab(nullptr),
80 kernel(nullptr),
81 loadAddrMask(p->load_addr_mask),
82 loadAddrOffset(p->load_offset),
83 nextPID(0),
84 physmem(name() + ".physmem", p->memories),
85 memoryMode(p->mem_mode),
86 _cacheLineSize(p->cache_line_size),
87 workItemsBegin(0),
88 workItemsEnd(0),
89 numWorkIds(p->num_work_ids),
90 _params(p),
91 totalNumInsts(0),
92 instEventQueue("system instruction-based event queue")
93 {
94 // add self to global system list
95 systemList.push_back(this);
96
97 if (FullSystem) {
98 kernelSymtab = new SymbolTable;
99 if (!debugSymbolTable)
100 debugSymbolTable = new SymbolTable;
101 }
102
103 // check if the cache line size is a value known to work
104 if (!(_cacheLineSize == 16 || _cacheLineSize == 32 ||
105 _cacheLineSize == 64 || _cacheLineSize == 128))
106 warn_once("Cache line size is neither 16, 32, 64 nor 128 bytes.\n");
107
108 // Get the generic system master IDs
109 MasterID tmp_id M5_VAR_USED;
110 tmp_id = getMasterId("writebacks");
111 assert(tmp_id == Request::wbMasterId);
112 tmp_id = getMasterId("functional");
113 assert(tmp_id == Request::funcMasterId);
114 tmp_id = getMasterId("interrupt");
115 assert(tmp_id == Request::intMasterId);
116
117 if (FullSystem) {
118 if (params()->kernel == "") {
119 inform("No kernel set for full system simulation. "
120 "Assuming you know what you're doing\n");
121 } else {
122 // Get the kernel code
123 kernel = createObjectFile(params()->kernel);
124 inform("kernel located at: %s", params()->kernel);
125
126 if (kernel == NULL)
127 fatal("Could not load kernel file %s", params()->kernel);
128
129 // setup entry points
130 kernelStart = kernel->textBase();
131 kernelEnd = kernel->bssBase() + kernel->bssSize();
132 kernelEntry = kernel->entryPoint();
133
134 // load symbols
135 if (!kernel->loadGlobalSymbols(kernelSymtab))
136 fatal("could not load kernel symbols\n");
137
138 if (!kernel->loadLocalSymbols(kernelSymtab))
139 fatal("could not load kernel local symbols\n");
140
141 if (!kernel->loadGlobalSymbols(debugSymbolTable))
142 fatal("could not load kernel symbols\n");
143
144 if (!kernel->loadLocalSymbols(debugSymbolTable))
145 fatal("could not load kernel local symbols\n");
146
147 // Loading only needs to happen once and after memory system is
148 // connected so it will happen in initState()
149 }
150 }
151
152 // increment the number of running systms
153 numSystemsRunning++;
154
155 // Set back pointers to the system in all memories
156 for (int x = 0; x < params()->memories.size(); x++)
157 params()->memories[x]->system(this);
158 }
159
160 System::~System()
161 {
162 delete kernelSymtab;
163 delete kernel;
164
165 for (uint32_t j = 0; j < numWorkIds; j++)
166 delete workItemStats[j];
167 }
168
169 void
170 System::init()
171 {
172 // check that the system port is connected
173 if (!_systemPort.isConnected())
174 panic("System port on %s is not connected.\n", name());
175 }
176
177 BaseMasterPort&
178 System::getMasterPort(const std::string &if_name, PortID idx)
179 {
180 // no need to distinguish at the moment (besides checking)
181 return _systemPort;
182 }
183
184 void
185 System::setMemoryMode(Enums::MemoryMode mode)
186 {
187 assert(getDrainState() == Drainable::Drained);
188 memoryMode = mode;
189 }
190
191 bool System::breakpoint()
192 {
193 if (remoteGDB.size())
194 return remoteGDB[0]->breakpoint();
195 return false;
196 }
197
198 /**
199 * Setting rgdb_wait to a positive integer waits for a remote debugger to
200 * connect to that context ID before continuing. This should really
201 be a parameter on the CPU object or something...
202 */
203 int rgdb_wait = -1;
204
205 int
206 System::registerThreadContext(ThreadContext *tc, int assigned)
207 {
208 int id;
209 if (assigned == -1) {
210 for (id = 0; id < threadContexts.size(); id++) {
211 if (!threadContexts[id])
212 break;
213 }
214
215 if (threadContexts.size() <= id)
216 threadContexts.resize(id + 1);
217 } else {
218 if (threadContexts.size() <= assigned)
219 threadContexts.resize(assigned + 1);
220 id = assigned;
221 }
222
223 if (threadContexts[id])
224 fatal("Cannot have two CPUs with the same id (%d)\n", id);
225
226 threadContexts[id] = tc;
227 _numContexts++;
228
229 #if THE_ISA != NULL_ISA
230 int port = getRemoteGDBPort();
231 if (port) {
232 RemoteGDB *rgdb = new RemoteGDB(this, tc);
233 GDBListener *gdbl = new GDBListener(rgdb, port + id);
234 gdbl->listen();
235
236 if (rgdb_wait != -1 && rgdb_wait == id)
237 gdbl->accept();
238
239 if (remoteGDB.size() <= id) {
240 remoteGDB.resize(id + 1);
241 }
242
243 remoteGDB[id] = rgdb;
244 }
245 #endif
246
247 activeCpus.push_back(false);
248
249 return id;
250 }
251
252 int
253 System::numRunningContexts()
254 {
255 int running = 0;
256 for (int i = 0; i < _numContexts; ++i) {
257 if (threadContexts[i]->status() != ThreadContext::Halted)
258 ++running;
259 }
260 return running;
261 }
262
263 void
264 System::initState()
265 {
266 if (FullSystem) {
267 for (int i = 0; i < threadContexts.size(); i++)
268 TheISA::startupCPU(threadContexts[i], i);
269 // Moved from the constructor to here since it relies on the
270 // address map being resolved in the interconnect
271 /**
272 * Load the kernel code into memory
273 */
274 if (params()->kernel != "") {
275 if (params()->kernel_addr_check) {
276 // Validate kernel mapping before loading binary
277 if (!(isMemAddr((kernelStart & loadAddrMask) +
278 loadAddrOffset) &&
279 isMemAddr((kernelEnd & loadAddrMask) +
280 loadAddrOffset))) {
281 fatal("Kernel is mapped to invalid location (not memory). "
282 "kernelStart 0x(%x) - kernelEnd 0x(%x) %#x:%#x\n",
283 kernelStart,
284 kernelEnd, (kernelStart & loadAddrMask) +
285 loadAddrOffset,
286 (kernelEnd & loadAddrMask) + loadAddrOffset);
287 }
288 }
289 // Load program sections into memory
290 kernel->loadSections(physProxy, loadAddrMask, loadAddrOffset);
291
292 DPRINTF(Loader, "Kernel start = %#x\n", kernelStart);
293 DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd);
294 DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry);
295 DPRINTF(Loader, "Kernel loaded...\n");
296 }
297 }
298
299 activeCpus.clear();
300 }
301
302 void
303 System::replaceThreadContext(ThreadContext *tc, int context_id)
304 {
305 if (context_id >= threadContexts.size()) {
306 panic("replaceThreadContext: bad id, %d >= %d\n",
307 context_id, threadContexts.size());
308 }
309
310 threadContexts[context_id] = tc;
311 if (context_id < remoteGDB.size())
312 remoteGDB[context_id]->replaceThreadContext(tc);
313 }
314
315 Addr
316 System::allocPhysPages(int npages)
317 {
318 Addr return_addr = pagePtr << PageShift;
319 pagePtr += npages;
320 if ((pagePtr << PageShift) > physmem.totalSize())
321 fatal("Out of memory, please increase size of physical memory.");
322 return return_addr;
323 }
324
325 Addr
326 System::memSize() const
327 {
328 return physmem.totalSize();
329 }
330
331 Addr
332 System::freeMemSize() const
333 {
334 return physmem.totalSize() - (pagePtr << PageShift);
335 }
336
337 bool
338 System::isMemAddr(Addr addr) const
339 {
340 return physmem.isMemAddr(addr);
341 }
342
343 unsigned int
344 System::drain(DrainManager *dm)
345 {
346 setDrainState(Drainable::Drained);
347 return 0;
348 }
349
350 void
351 System::drainResume()
352 {
353 Drainable::drainResume();
354 totalNumInsts = 0;
355 }
356
357 void
358 System::serialize(ostream &os)
359 {
360 if (FullSystem)
361 kernelSymtab->serialize("kernel_symtab", os);
362 SERIALIZE_SCALAR(pagePtr);
363 SERIALIZE_SCALAR(nextPID);
364 serializeSymtab(os);
365
366 // also serialize the memories in the system
367 nameOut(os, csprintf("%s.physmem", name()));
368 physmem.serialize(os);
369 }
370
371
372 void
373 System::unserialize(Checkpoint *cp, const string &section)
374 {
375 if (FullSystem)
376 kernelSymtab->unserialize("kernel_symtab", cp, section);
377 UNSERIALIZE_SCALAR(pagePtr);
378 UNSERIALIZE_SCALAR(nextPID);
379 unserializeSymtab(cp, section);
380
381 // also unserialize the memories in the system
382 physmem.unserialize(cp, csprintf("%s.physmem", name()));
383 }
384
385 void
386 System::regStats()
387 {
388 for (uint32_t j = 0; j < numWorkIds ; j++) {
389 workItemStats[j] = new Stats::Histogram();
390 stringstream namestr;
391 ccprintf(namestr, "work_item_type%d", j);
392 workItemStats[j]->init(20)
393 .name(name() + "." + namestr.str())
394 .desc("Run time stat for" + namestr.str())
395 .prereq(*workItemStats[j]);
396 }
397 }
398
399 void
400 System::workItemEnd(uint32_t tid, uint32_t workid)
401 {
402 std::pair<uint32_t,uint32_t> p(tid, workid);
403 if (!lastWorkItemStarted.count(p))
404 return;
405
406 Tick samp = curTick() - lastWorkItemStarted[p];
407 DPRINTF(WorkItems, "Work item end: %d\t%d\t%lld\n", tid, workid, samp);
408
409 if (workid >= numWorkIds)
410 fatal("Got workid greater than specified in system configuration\n");
411
412 workItemStats[workid]->sample(samp);
413 lastWorkItemStarted.erase(p);
414 }
415
416 void
417 System::printSystems()
418 {
419 ios::fmtflags flags(cerr.flags());
420
421 vector<System *>::iterator i = systemList.begin();
422 vector<System *>::iterator end = systemList.end();
423 for (; i != end; ++i) {
424 System *sys = *i;
425 cerr << "System " << sys->name() << ": " << hex << sys << endl;
426 }
427
428 cerr.flags(flags);
429 }
430
431 void
432 printSystems()
433 {
434 System::printSystems();
435 }
436
437 MasterID
438 System::getMasterId(std::string master_name)
439 {
440 // strip off system name if the string starts with it
441 if (startswith(master_name, name()))
442 master_name = master_name.erase(0, name().size() + 1);
443
444 // CPUs in switch_cpus ask for ids again after switching
445 for (int i = 0; i < masterIds.size(); i++) {
446 if (masterIds[i] == master_name) {
447 return i;
448 }
449 }
450
451 // Verify that the statistics haven't been enabled yet
452 // Otherwise objects will have sized their stat buckets and
453 // they will be too small
454
455 if (Stats::enabled()) {
456 fatal("Can't request a masterId after regStats(). "
457 "You must do so in init().\n");
458 }
459
460 masterIds.push_back(master_name);
461
462 return masterIds.size() - 1;
463 }
464
465 std::string
466 System::getMasterName(MasterID master_id)
467 {
468 if (master_id >= masterIds.size())
469 fatal("Invalid master_id passed to getMasterName()\n");
470
471 return masterIds[master_id];
472 }
473
474 System *
475 SystemParams::create()
476 {
477 return new System(this);
478 }