base,sim: Move DTRACE into base/debug.hh.
[gem5.git] / src / sim / system.cc
1 /*
2 * Copyright (c) 2011-2014,2017-2019 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
42 #include "sim/system.hh"
43
44 #include <algorithm>
45
46 #include "arch/remote_gdb.hh"
47 #include "arch/utility.hh"
48 #include "base/loader/object_file.hh"
49 #include "base/loader/symtab.hh"
50 #include "base/str.hh"
51 #include "base/trace.hh"
52 #include "config/use_kvm.hh"
53 #if USE_KVM
54 #include "cpu/kvm/base.hh"
55 #include "cpu/kvm/vm.hh"
56 #endif
57 #include "cpu/base.hh"
58 #include "cpu/thread_context.hh"
59 #include "debug/Loader.hh"
60 #include "debug/WorkItems.hh"
61 #include "mem/abstract_mem.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/redirect_path.hh"
68
69 /**
70 * To avoid linking errors with LTO, only include the header if we
71 * actually have a definition.
72 */
73 #if THE_ISA != NULL_ISA
74 #include "kern/kernel_stats.hh"
75
76 #endif
77
78 using namespace std;
79 using namespace TheISA;
80
81 vector<System *> System::systemList;
82
83 int System::numSystemsRunning = 0;
84
85 System::System(Params *p)
86 : SimObject(p), _systemPort("system_port", this),
87 multiThread(p->multi_thread),
88 pagePtr(0),
89 init_param(p->init_param),
90 physProxy(_systemPort, p->cache_line_size),
91 workload(p->workload),
92 #if USE_KVM
93 kvmVM(p->kvm_vm),
94 #else
95 kvmVM(nullptr),
96 #endif
97 physmem(name() + ".physmem", p->memories, p->mmap_using_noreserve),
98 memoryMode(p->mem_mode),
99 _cacheLineSize(p->cache_line_size),
100 workItemsBegin(0),
101 workItemsEnd(0),
102 numWorkIds(p->num_work_ids),
103 thermalModel(p->thermal_model),
104 _params(p),
105 _m5opRange(p->m5ops_base ?
106 RangeSize(p->m5ops_base, 0x10000) :
107 AddrRange(1, 0)), // Create an empty range if disabled
108 totalNumInsts(0),
109 redirectPaths(p->redirect_paths)
110 {
111 if (workload)
112 workload->system = this;
113
114 // add self to global system list
115 systemList.push_back(this);
116
117 #if USE_KVM
118 if (kvmVM) {
119 kvmVM->setSystem(this);
120 }
121 #endif
122
123 // check if the cache line size is a value known to work
124 if (!(_cacheLineSize == 16 || _cacheLineSize == 32 ||
125 _cacheLineSize == 64 || _cacheLineSize == 128))
126 warn_once("Cache line size is neither 16, 32, 64 nor 128 bytes.\n");
127
128 // Get the generic system master IDs
129 MasterID tmp_id M5_VAR_USED;
130 tmp_id = getMasterId(this, "writebacks");
131 assert(tmp_id == Request::wbMasterId);
132 tmp_id = getMasterId(this, "functional");
133 assert(tmp_id == Request::funcMasterId);
134 tmp_id = getMasterId(this, "interrupt");
135 assert(tmp_id == Request::intMasterId);
136
137 // increment the number of running systems
138 numSystemsRunning++;
139
140 // Set back pointers to the system in all memories
141 for (int x = 0; x < params()->memories.size(); x++)
142 params()->memories[x]->system(this);
143 }
144
145 System::~System()
146 {
147 for (uint32_t j = 0; j < numWorkIds; j++)
148 delete workItemStats[j];
149 }
150
151 void
152 System::init()
153 {
154 // check that the system port is connected
155 if (!_systemPort.isConnected())
156 panic("System port on %s is not connected.\n", name());
157 }
158
159 void
160 System::startup()
161 {
162 SimObject::startup();
163
164 // Now that we're about to start simulation, wait for GDB connections if
165 // requested.
166 #if THE_ISA != NULL_ISA
167 for (auto *tc: threadContexts) {
168 auto *cpu = tc->getCpuPtr();
169 auto id = tc->contextId();
170 if (remoteGDB.size() <= id)
171 continue;
172 auto *rgdb = remoteGDB[id];
173
174 if (cpu->waitForRemoteGDB()) {
175 inform("%s: Waiting for a remote GDB connection on port %d.\n",
176 cpu->name(), rgdb->port());
177
178 rgdb->connect();
179 }
180 }
181 #endif
182 }
183
184 Port &
185 System::getPort(const std::string &if_name, PortID idx)
186 {
187 // no need to distinguish at the moment (besides checking)
188 return _systemPort;
189 }
190
191 void
192 System::setMemoryMode(Enums::MemoryMode mode)
193 {
194 assert(drainState() == DrainState::Drained);
195 memoryMode = mode;
196 }
197
198 bool System::breakpoint()
199 {
200 if (remoteGDB.size())
201 return remoteGDB[0]->breakpoint();
202 return false;
203 }
204
205 ContextID
206 System::registerThreadContext(ThreadContext *tc, ContextID assigned)
207 {
208 int id = assigned;
209 if (id == InvalidContextID) {
210 // Find an unused context ID for this thread.
211 id = 0;
212 while (id < threadContexts.size() && threadContexts[id])
213 id++;
214 }
215
216 if (threadContexts.size() <= id)
217 threadContexts.resize(id + 1);
218
219 fatal_if(threadContexts[id],
220 "Cannot have two CPUs with the same id (%d)\n", id);
221
222 threadContexts[id] = tc;
223 for (auto *e: liveEvents)
224 tc->schedule(e);
225
226 #if THE_ISA != NULL_ISA
227 int port = getRemoteGDBPort();
228 if (port) {
229 RemoteGDB *rgdb = new RemoteGDB(this, tc, port + id);
230 rgdb->listen();
231
232 if (remoteGDB.size() <= id)
233 remoteGDB.resize(id + 1);
234
235 remoteGDB[id] = rgdb;
236 }
237 #endif
238
239 activeCpus.push_back(false);
240
241 return id;
242 }
243
244 ThreadContext *
245 System::findFreeContext()
246 {
247 for (auto &it : threadContexts) {
248 if (ThreadContext::Halted == it->status())
249 return it;
250 }
251 return nullptr;
252 }
253
254 bool
255 System::schedule(PCEvent *event)
256 {
257 bool all = true;
258 liveEvents.push_back(event);
259 for (auto *tc: threadContexts)
260 all = tc->schedule(event) && all;
261 return all;
262 }
263
264 bool
265 System::remove(PCEvent *event)
266 {
267 bool all = true;
268 liveEvents.remove(event);
269 for (auto *tc: threadContexts)
270 all = tc->remove(event) && all;
271 return all;
272 }
273
274 int
275 System::numRunningContexts()
276 {
277 return std::count_if(
278 threadContexts.cbegin(),
279 threadContexts.cend(),
280 [] (ThreadContext* tc) {
281 return ((tc->status() != ThreadContext::Halted) &&
282 (tc->status() != ThreadContext::Halting));
283 }
284 );
285 }
286
287 void
288 System::replaceThreadContext(ThreadContext *tc, ContextID context_id)
289 {
290 if (context_id >= threadContexts.size()) {
291 panic("replaceThreadContext: bad id, %d >= %d\n",
292 context_id, threadContexts.size());
293 }
294
295 for (auto *e: liveEvents) {
296 threadContexts[context_id]->remove(e);
297 tc->schedule(e);
298 }
299 threadContexts[context_id] = tc;
300 if (context_id < remoteGDB.size())
301 remoteGDB[context_id]->replaceThreadContext(tc);
302 }
303
304 bool
305 System::validKvmEnvironment() const
306 {
307 #if USE_KVM
308 if (threadContexts.empty())
309 return false;
310
311 for (auto tc : threadContexts) {
312 if (dynamic_cast<BaseKvmCPU*>(tc->getCpuPtr()) == nullptr) {
313 return false;
314 }
315 }
316 return true;
317 #else
318 return false;
319 #endif
320 }
321
322 Addr
323 System::allocPhysPages(int npages)
324 {
325 Addr return_addr = pagePtr << PageShift;
326 pagePtr += npages;
327
328 Addr next_return_addr = pagePtr << PageShift;
329
330 if (_m5opRange.contains(next_return_addr)) {
331 warn("Reached m5ops MMIO region\n");
332 return_addr = 0xffffffff;
333 pagePtr = 0xffffffff >> PageShift;
334 }
335
336 if ((pagePtr << PageShift) > physmem.totalSize())
337 fatal("Out of memory, please increase size of physical memory.");
338 return return_addr;
339 }
340
341 Addr
342 System::memSize() const
343 {
344 return physmem.totalSize();
345 }
346
347 Addr
348 System::freeMemSize() const
349 {
350 return physmem.totalSize() - (pagePtr << PageShift);
351 }
352
353 bool
354 System::isMemAddr(Addr addr) const
355 {
356 return physmem.isMemAddr(addr);
357 }
358
359 void
360 System::drainResume()
361 {
362 totalNumInsts = 0;
363 }
364
365 void
366 System::serialize(CheckpointOut &cp) const
367 {
368 SERIALIZE_SCALAR(pagePtr);
369
370 // also serialize the memories in the system
371 physmem.serializeSection(cp, "physmem");
372 }
373
374
375 void
376 System::unserialize(CheckpointIn &cp)
377 {
378 UNSERIALIZE_SCALAR(pagePtr);
379
380 // also unserialize the memories in the system
381 physmem.unserializeSection(cp, "physmem");
382 }
383
384 void
385 System::regStats()
386 {
387 SimObject::regStats();
388
389 for (uint32_t j = 0; j < numWorkIds ; j++) {
390 workItemStats[j] = new Stats::Histogram();
391 stringstream namestr;
392 ccprintf(namestr, "work_item_type%d", j);
393 workItemStats[j]->init(20)
394 .name(name() + "." + namestr.str())
395 .desc("Run time stat for" + namestr.str())
396 .prereq(*workItemStats[j]);
397 }
398 }
399
400 void
401 System::workItemEnd(uint32_t tid, uint32_t workid)
402 {
403 std::pair<uint32_t,uint32_t> p(tid, workid);
404 if (!lastWorkItemStarted.count(p))
405 return;
406
407 Tick samp = curTick() - lastWorkItemStarted[p];
408 DPRINTF(WorkItems, "Work item end: %d\t%d\t%lld\n", tid, workid, samp);
409
410 if (workid >= numWorkIds)
411 fatal("Got workid greater than specified in system configuration\n");
412
413 workItemStats[workid]->sample(samp);
414 lastWorkItemStarted.erase(p);
415 }
416
417 void
418 System::printSystems()
419 {
420 ios::fmtflags flags(cerr.flags());
421
422 vector<System *>::iterator i = systemList.begin();
423 vector<System *>::iterator end = systemList.end();
424 for (; i != end; ++i) {
425 System *sys = *i;
426 cerr << "System " << sys->name() << ": " << hex << sys << endl;
427 }
428
429 cerr.flags(flags);
430 }
431
432 void
433 printSystems()
434 {
435 System::printSystems();
436 }
437
438 std::string
439 System::stripSystemName(const std::string& master_name) const
440 {
441 if (startswith(master_name, name())) {
442 return master_name.substr(name().size());
443 } else {
444 return master_name;
445 }
446 }
447
448 MasterID
449 System::lookupMasterId(const SimObject* obj) const
450 {
451 MasterID id = Request::invldMasterId;
452
453 // number of occurrences of the SimObject pointer
454 // in the master list.
455 auto obj_number = 0;
456
457 for (int i = 0; i < masters.size(); i++) {
458 if (masters[i].obj == obj) {
459 id = i;
460 obj_number++;
461 }
462 }
463
464 fatal_if(obj_number > 1,
465 "Cannot lookup MasterID by SimObject pointer: "
466 "More than one master is sharing the same SimObject\n");
467
468 return id;
469 }
470
471 MasterID
472 System::lookupMasterId(const std::string& master_name) const
473 {
474 std::string name = stripSystemName(master_name);
475
476 for (int i = 0; i < masters.size(); i++) {
477 if (masters[i].masterName == name) {
478 return i;
479 }
480 }
481
482 return Request::invldMasterId;
483 }
484
485 MasterID
486 System::getGlobalMasterId(const std::string& master_name)
487 {
488 return _getMasterId(nullptr, master_name);
489 }
490
491 MasterID
492 System::getMasterId(const SimObject* master, std::string submaster)
493 {
494 auto master_name = leafMasterName(master, submaster);
495 return _getMasterId(master, master_name);
496 }
497
498 MasterID
499 System::_getMasterId(const SimObject* master, const std::string& master_name)
500 {
501 std::string name = stripSystemName(master_name);
502
503 // CPUs in switch_cpus ask for ids again after switching
504 for (int i = 0; i < masters.size(); i++) {
505 if (masters[i].masterName == name) {
506 return i;
507 }
508 }
509
510 // Verify that the statistics haven't been enabled yet
511 // Otherwise objects will have sized their stat buckets and
512 // they will be too small
513
514 if (Stats::enabled()) {
515 fatal("Can't request a masterId after regStats(). "
516 "You must do so in init().\n");
517 }
518
519 // Generate a new MasterID incrementally
520 MasterID master_id = masters.size();
521
522 // Append the new Master metadata to the group of system Masters.
523 masters.emplace_back(master, name, master_id);
524
525 return masters.back().masterId;
526 }
527
528 std::string
529 System::leafMasterName(const SimObject* master, const std::string& submaster)
530 {
531 if (submaster.empty()) {
532 return master->name();
533 } else {
534 // Get the full master name by appending the submaster name to
535 // the root SimObject master name
536 return master->name() + "." + submaster;
537 }
538 }
539
540 std::string
541 System::getMasterName(MasterID master_id)
542 {
543 if (master_id >= masters.size())
544 fatal("Invalid master_id passed to getMasterName()\n");
545
546 const auto& master_info = masters[master_id];
547 return master_info.masterName;
548 }
549
550 System *
551 SystemParams::create()
552 {
553 return new System(this);
554 }