misc: Merge branch 'release-staging-v20.1.0.0' into develop
[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/compiler.hh"
49 #include "base/loader/object_file.hh"
50 #include "base/loader/symtab.hh"
51 #include "base/str.hh"
52 #include "base/trace.hh"
53 #include "config/the_isa.hh"
54 #include "config/use_kvm.hh"
55 #if USE_KVM
56 #include "cpu/kvm/base.hh"
57 #include "cpu/kvm/vm.hh"
58 #endif
59 #if THE_ISA != NULL_ISA
60 #include "cpu/base.hh"
61 #endif
62 #include "cpu/thread_context.hh"
63 #include "debug/Loader.hh"
64 #include "debug/Quiesce.hh"
65 #include "debug/WorkItems.hh"
66 #include "mem/abstract_mem.hh"
67 #include "mem/physical.hh"
68 #include "params/System.hh"
69 #include "sim/byteswap.hh"
70 #include "sim/debug.hh"
71 #include "sim/full_system.hh"
72 #include "sim/redirect_path.hh"
73
74 using namespace std;
75 using namespace TheISA;
76
77 vector<System *> System::systemList;
78
79 void
80 System::Threads::Thread::resume()
81 {
82 # if THE_ISA != NULL_ISA
83 DPRINTFS(Quiesce, context->getCpuPtr(), "activating\n");
84 context->activate();
85 # endif
86 }
87
88 std::string
89 System::Threads::Thread::name() const
90 {
91 assert(context);
92 return csprintf("%s.threads[%d]", context->getSystemPtr()->name(),
93 context->contextId());
94 }
95
96 void
97 System::Threads::Thread::quiesce() const
98 {
99 context->suspend();
100 auto *workload = context->getSystemPtr()->workload;
101 if (workload)
102 workload->recordQuiesce();
103 }
104
105 ContextID
106 System::Threads::insert(ThreadContext *tc, ContextID id)
107 {
108 if (id == InvalidContextID) {
109 for (id = 0; id < size(); id++) {
110 if (!threads[id].context)
111 break;
112 }
113 }
114
115 if (id >= size())
116 threads.resize(id + 1);
117
118 fatal_if(threads[id].context,
119 "Cannot have two thread contexts with the same id (%d).", id);
120
121 auto *sys = tc->getSystemPtr();
122
123 auto &t = thread(id);
124 t.context = tc;
125 // Look up this thread again on resume, in case the threads vector has
126 // been reallocated.
127 t.resumeEvent = new EventFunctionWrapper(
128 [this, id](){ thread(id).resume(); }, sys->name());
129 # if THE_ISA != NULL_ISA
130 int port = getRemoteGDBPort();
131 if (port) {
132 t.gdb = new RemoteGDB(sys, tc, port + id);
133 t.gdb->listen();
134 }
135 # endif
136
137 return id;
138 }
139
140 void
141 System::Threads::replace(ThreadContext *tc, ContextID id)
142 {
143 auto &t = thread(id);
144 panic_if(!t.context, "Can't replace a context which doesn't exist.");
145 if (t.gdb)
146 t.gdb->replaceThreadContext(tc);
147 # if THE_ISA != NULL_ISA
148 if (t.resumeEvent->scheduled()) {
149 Tick when = t.resumeEvent->when();
150 t.context->getCpuPtr()->deschedule(t.resumeEvent);
151 tc->getCpuPtr()->schedule(t.resumeEvent, when);
152 }
153 # endif
154 t.context = tc;
155 }
156
157 ThreadContext *
158 System::Threads::findFree()
159 {
160 for (auto &thread: threads) {
161 if (thread.context->status() == ThreadContext::Halted)
162 return thread.context;
163 }
164 return nullptr;
165 }
166
167 int
168 System::Threads::numRunning() const
169 {
170 int count = 0;
171 for (auto &thread: threads) {
172 auto status = thread.context->status();
173 if (status != ThreadContext::Halted &&
174 status != ThreadContext::Halting) {
175 count++;
176 }
177 }
178 return count;
179 }
180
181 void
182 System::Threads::quiesce(ContextID id)
183 {
184 auto &t = thread(id);
185 # if THE_ISA != NULL_ISA
186 M5_VAR_USED BaseCPU *cpu = t.context->getCpuPtr();
187 DPRINTFS(Quiesce, cpu, "quiesce()\n");
188 # endif
189 t.quiesce();
190 }
191
192 void
193 System::Threads::quiesceTick(ContextID id, Tick when)
194 {
195 # if THE_ISA != NULL_ISA
196 auto &t = thread(id);
197 BaseCPU *cpu = t.context->getCpuPtr();
198
199 DPRINTFS(Quiesce, cpu, "quiesceTick until %u\n", when);
200 t.quiesce();
201
202 cpu->reschedule(t.resumeEvent, when, true);
203 # endif
204 }
205
206 int System::numSystemsRunning = 0;
207
208 System::System(Params *p)
209 : SimObject(p), _systemPort("system_port", this),
210 multiThread(p->multi_thread),
211 pagePtr(0),
212 init_param(p->init_param),
213 physProxy(_systemPort, p->cache_line_size),
214 workload(p->workload),
215 #if USE_KVM
216 kvmVM(p->kvm_vm),
217 #else
218 kvmVM(nullptr),
219 #endif
220 physmem(name() + ".physmem", p->memories, p->mmap_using_noreserve,
221 p->shared_backstore),
222 memoryMode(p->mem_mode),
223 _cacheLineSize(p->cache_line_size),
224 workItemsBegin(0),
225 workItemsEnd(0),
226 numWorkIds(p->num_work_ids),
227 thermalModel(p->thermal_model),
228 _params(p),
229 _m5opRange(p->m5ops_base ?
230 RangeSize(p->m5ops_base, 0x10000) :
231 AddrRange(1, 0)), // Create an empty range if disabled
232 totalNumInsts(0),
233 redirectPaths(p->redirect_paths)
234 {
235 if (workload)
236 workload->system = this;
237
238 // add self to global system list
239 systemList.push_back(this);
240
241 #if USE_KVM
242 if (kvmVM) {
243 kvmVM->setSystem(this);
244 }
245 #endif
246
247 // check if the cache line size is a value known to work
248 if (!(_cacheLineSize == 16 || _cacheLineSize == 32 ||
249 _cacheLineSize == 64 || _cacheLineSize == 128))
250 warn_once("Cache line size is neither 16, 32, 64 nor 128 bytes.\n");
251
252 // Get the generic system requestor IDs
253 M5_VAR_USED RequestorID tmp_id;
254 tmp_id = getRequestorId(this, "writebacks");
255 assert(tmp_id == Request::wbRequestorId);
256 tmp_id = getRequestorId(this, "functional");
257 assert(tmp_id == Request::funcRequestorId);
258 tmp_id = getRequestorId(this, "interrupt");
259 assert(tmp_id == Request::intRequestorId);
260
261 // increment the number of running systems
262 numSystemsRunning++;
263
264 // Set back pointers to the system in all memories
265 for (int x = 0; x < params()->memories.size(); x++)
266 params()->memories[x]->system(this);
267 }
268
269 System::~System()
270 {
271 for (uint32_t j = 0; j < numWorkIds; j++)
272 delete workItemStats[j];
273 }
274
275 void
276 System::startup()
277 {
278 SimObject::startup();
279
280 // Now that we're about to start simulation, wait for GDB connections if
281 // requested.
282 #if THE_ISA != NULL_ISA
283 for (int i = 0; i < threads.size(); i++) {
284 auto *gdb = threads.thread(i).gdb;
285 auto *cpu = threads[i]->getCpuPtr();
286 if (gdb && cpu->waitForRemoteGDB()) {
287 inform("%s: Waiting for a remote GDB connection on port %d.",
288 cpu->name(), gdb->port());
289 gdb->connect();
290 }
291 }
292 #endif
293 }
294
295 Port &
296 System::getPort(const std::string &if_name, PortID idx)
297 {
298 // no need to distinguish at the moment (besides checking)
299 return _systemPort;
300 }
301
302 void
303 System::setMemoryMode(Enums::MemoryMode mode)
304 {
305 assert(drainState() == DrainState::Drained);
306 memoryMode = mode;
307 }
308
309 bool System::breakpoint()
310 {
311 if (!threads.size())
312 return false;
313 auto *gdb = threads.thread(0).gdb;
314 if (!gdb)
315 return false;
316 return gdb->breakpoint();
317 }
318
319 ContextID
320 System::registerThreadContext(ThreadContext *tc, ContextID assigned)
321 {
322 ContextID id = threads.insert(tc, assigned);
323
324 for (auto *e: liveEvents)
325 tc->schedule(e);
326
327 return id;
328 }
329
330 bool
331 System::schedule(PCEvent *event)
332 {
333 bool all = true;
334 liveEvents.push_back(event);
335 for (auto *tc: threads)
336 all = tc->schedule(event) && all;
337 return all;
338 }
339
340 bool
341 System::remove(PCEvent *event)
342 {
343 bool all = true;
344 liveEvents.remove(event);
345 for (auto *tc: threads)
346 all = tc->remove(event) && all;
347 return all;
348 }
349
350 void
351 System::replaceThreadContext(ThreadContext *tc, ContextID context_id)
352 {
353 auto *otc = threads[context_id];
354 threads.replace(tc, context_id);
355
356 for (auto *e: liveEvents) {
357 otc->remove(e);
358 tc->schedule(e);
359 }
360 }
361
362 bool
363 System::validKvmEnvironment() const
364 {
365 #if USE_KVM
366 if (threads.empty())
367 return false;
368
369 for (auto *tc: threads) {
370 if (!dynamic_cast<BaseKvmCPU *>(tc->getCpuPtr()))
371 return false;
372 }
373
374 return true;
375 #else
376 return false;
377 #endif
378 }
379
380 Addr
381 System::allocPhysPages(int npages)
382 {
383 Addr return_addr = pagePtr << PageShift;
384 pagePtr += npages;
385
386 Addr next_return_addr = pagePtr << PageShift;
387
388 if (_m5opRange.contains(next_return_addr)) {
389 warn("Reached m5ops MMIO region\n");
390 return_addr = 0xffffffff;
391 pagePtr = 0xffffffff >> PageShift;
392 }
393
394 if ((pagePtr << PageShift) > physmem.totalSize())
395 fatal("Out of memory, please increase size of physical memory.");
396 return return_addr;
397 }
398
399 Addr
400 System::memSize() const
401 {
402 return physmem.totalSize();
403 }
404
405 Addr
406 System::freeMemSize() const
407 {
408 return physmem.totalSize() - (pagePtr << PageShift);
409 }
410
411 bool
412 System::isMemAddr(Addr addr) const
413 {
414 return physmem.isMemAddr(addr);
415 }
416
417 void
418 System::addDeviceMemory(RequestorID requestor_id, AbstractMemory *deviceMemory)
419 {
420 if (!deviceMemMap.count(requestor_id)) {
421 deviceMemMap.insert(std::make_pair(requestor_id, deviceMemory));
422 }
423 }
424
425 bool
426 System::isDeviceMemAddr(PacketPtr pkt) const
427 {
428 const RequestorID& id = pkt->requestorId();
429
430 return (deviceMemMap.count(id) &&
431 deviceMemMap.at(id)->getAddrRange().contains(pkt->getAddr()));
432 }
433
434 AbstractMemory *
435 System::getDeviceMemory(RequestorID id) const
436 {
437 panic_if(!deviceMemMap.count(id),
438 "No device memory found for RequestorID %d\n", id);
439 return deviceMemMap.at(id);
440 }
441
442 void
443 System::drainResume()
444 {
445 totalNumInsts = 0;
446 }
447
448 void
449 System::serialize(CheckpointOut &cp) const
450 {
451 SERIALIZE_SCALAR(pagePtr);
452
453 for (auto &t: threads.threads) {
454 Tick when = 0;
455 if (t.resumeEvent && t.resumeEvent->scheduled())
456 when = t.resumeEvent->when();
457 ContextID id = t.context->contextId();
458 paramOut(cp, csprintf("quiesceEndTick_%d", id), when);
459 }
460
461 // also serialize the memories in the system
462 physmem.serializeSection(cp, "physmem");
463 }
464
465
466 void
467 System::unserialize(CheckpointIn &cp)
468 {
469 UNSERIALIZE_SCALAR(pagePtr);
470
471 for (auto &t: threads.threads) {
472 Tick when = 0;
473 ContextID id = t.context->contextId();
474 if (!optParamIn(cp, csprintf("quiesceEndTick_%d", id), when) ||
475 !when || !t.resumeEvent) {
476 continue;
477 }
478 # if THE_ISA != NULL_ISA
479 t.context->getCpuPtr()->schedule(t.resumeEvent, when);
480 # endif
481 }
482
483 // also unserialize the memories in the system
484 physmem.unserializeSection(cp, "physmem");
485 }
486
487 void
488 System::regStats()
489 {
490 SimObject::regStats();
491
492 for (uint32_t j = 0; j < numWorkIds ; j++) {
493 workItemStats[j] = new Stats::Histogram();
494 stringstream namestr;
495 ccprintf(namestr, "work_item_type%d", j);
496 workItemStats[j]->init(20)
497 .name(name() + "." + namestr.str())
498 .desc("Run time stat for" + namestr.str())
499 .prereq(*workItemStats[j]);
500 }
501 }
502
503 void
504 System::workItemEnd(uint32_t tid, uint32_t workid)
505 {
506 std::pair<uint32_t,uint32_t> p(tid, workid);
507 if (!lastWorkItemStarted.count(p))
508 return;
509
510 Tick samp = curTick() - lastWorkItemStarted[p];
511 DPRINTF(WorkItems, "Work item end: %d\t%d\t%lld\n", tid, workid, samp);
512
513 if (workid >= numWorkIds)
514 fatal("Got workid greater than specified in system configuration\n");
515
516 workItemStats[workid]->sample(samp);
517 lastWorkItemStarted.erase(p);
518 }
519
520 void
521 System::printSystems()
522 {
523 ios::fmtflags flags(cerr.flags());
524
525 vector<System *>::iterator i = systemList.begin();
526 vector<System *>::iterator end = systemList.end();
527 for (; i != end; ++i) {
528 System *sys = *i;
529 cerr << "System " << sys->name() << ": " << hex << sys << endl;
530 }
531
532 cerr.flags(flags);
533 }
534
535 void
536 printSystems()
537 {
538 System::printSystems();
539 }
540
541 std::string
542 System::stripSystemName(const std::string& requestor_name) const
543 {
544 if (startswith(requestor_name, name())) {
545 return requestor_name.substr(name().size());
546 } else {
547 return requestor_name;
548 }
549 }
550
551 RequestorID
552 System::lookupRequestorId(const SimObject* obj) const
553 {
554 RequestorID id = Request::invldRequestorId;
555
556 // number of occurrences of the SimObject pointer
557 // in the requestor list.
558 auto obj_number = 0;
559
560 for (int i = 0; i < requestors.size(); i++) {
561 if (requestors[i].obj == obj) {
562 id = i;
563 obj_number++;
564 }
565 }
566
567 fatal_if(obj_number > 1,
568 "Cannot lookup RequestorID by SimObject pointer: "
569 "More than one requestor is sharing the same SimObject\n");
570
571 return id;
572 }
573
574 RequestorID
575 System::lookupRequestorId(const std::string& requestor_name) const
576 {
577 std::string name = stripSystemName(requestor_name);
578
579 for (int i = 0; i < requestors.size(); i++) {
580 if (requestors[i].req_name == name) {
581 return i;
582 }
583 }
584
585 return Request::invldRequestorId;
586 }
587
588 RequestorID
589 System::getGlobalRequestorId(const std::string& requestor_name)
590 {
591 return _getRequestorId(nullptr, requestor_name);
592 }
593
594 RequestorID
595 System::getRequestorId(const SimObject* requestor, std::string subrequestor)
596 {
597 auto requestor_name = leafRequestorName(requestor, subrequestor);
598 return _getRequestorId(requestor, requestor_name);
599 }
600
601 RequestorID
602 System::_getRequestorId(const SimObject* requestor,
603 const std::string& requestor_name)
604 {
605 std::string name = stripSystemName(requestor_name);
606
607 // CPUs in switch_cpus ask for ids again after switching
608 for (int i = 0; i < requestors.size(); i++) {
609 if (requestors[i].req_name == name) {
610 return i;
611 }
612 }
613
614 // Verify that the statistics haven't been enabled yet
615 // Otherwise objects will have sized their stat buckets and
616 // they will be too small
617
618 if (Stats::enabled()) {
619 fatal("Can't request a requestorId after regStats(). "
620 "You must do so in init().\n");
621 }
622
623 // Generate a new RequestorID incrementally
624 RequestorID requestor_id = requestors.size();
625
626 // Append the new Requestor metadata to the group of system Requestors.
627 requestors.emplace_back(requestor, name, requestor_id);
628
629 return requestors.back().id;
630 }
631
632 std::string
633 System::leafRequestorName(const SimObject* requestor,
634 const std::string& subrequestor)
635 {
636 if (subrequestor.empty()) {
637 return requestor->name();
638 } else {
639 // Get the full requestor name by appending the subrequestor name to
640 // the root SimObject requestor name
641 return requestor->name() + "." + subrequestor;
642 }
643 }
644
645 std::string
646 System::getRequestorName(RequestorID requestor_id)
647 {
648 if (requestor_id >= requestors.size())
649 fatal("Invalid requestor_id passed to getRequestorName()\n");
650
651 const auto& requestor_info = requestors[requestor_id];
652 return requestor_info.req_name;
653 }
654
655 System *
656 SystemParams::create()
657 {
658 return new System(this);
659 }