base, sim, mem, arch: Remove the dummy CPU in NULL
[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 BaseCPU M5_VAR_USED *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 RequestorID tmp_id M5_VAR_USED;
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::init()
277 {
278 // check that the system port is connected
279 if (!_systemPort.isConnected())
280 panic("System port on %s is not connected.\n", name());
281 }
282
283 void
284 System::startup()
285 {
286 SimObject::startup();
287
288 // Now that we're about to start simulation, wait for GDB connections if
289 // requested.
290 #if THE_ISA != NULL_ISA
291 for (int i = 0; i < threads.size(); i++) {
292 auto *gdb = threads.thread(i).gdb;
293 auto *cpu = threads[i]->getCpuPtr();
294 if (gdb && cpu->waitForRemoteGDB()) {
295 inform("%s: Waiting for a remote GDB connection on port %d.",
296 cpu->name(), gdb->port());
297 gdb->connect();
298 }
299 }
300 #endif
301 }
302
303 Port &
304 System::getPort(const std::string &if_name, PortID idx)
305 {
306 // no need to distinguish at the moment (besides checking)
307 return _systemPort;
308 }
309
310 void
311 System::setMemoryMode(Enums::MemoryMode mode)
312 {
313 assert(drainState() == DrainState::Drained);
314 memoryMode = mode;
315 }
316
317 bool System::breakpoint()
318 {
319 if (!threads.size())
320 return false;
321 auto *gdb = threads.thread(0).gdb;
322 if (!gdb)
323 return false;
324 return gdb->breakpoint();
325 }
326
327 ContextID
328 System::registerThreadContext(ThreadContext *tc, ContextID assigned)
329 {
330 ContextID id = threads.insert(tc, assigned);
331
332 for (auto *e: liveEvents)
333 tc->schedule(e);
334
335 return id;
336 }
337
338 bool
339 System::schedule(PCEvent *event)
340 {
341 bool all = true;
342 liveEvents.push_back(event);
343 for (auto *tc: threads)
344 all = tc->schedule(event) && all;
345 return all;
346 }
347
348 bool
349 System::remove(PCEvent *event)
350 {
351 bool all = true;
352 liveEvents.remove(event);
353 for (auto *tc: threads)
354 all = tc->remove(event) && all;
355 return all;
356 }
357
358 void
359 System::replaceThreadContext(ThreadContext *tc, ContextID context_id)
360 {
361 auto *otc = threads[context_id];
362 threads.replace(tc, context_id);
363
364 for (auto *e: liveEvents) {
365 otc->remove(e);
366 tc->schedule(e);
367 }
368 }
369
370 bool
371 System::validKvmEnvironment() const
372 {
373 #if USE_KVM
374 if (threads.empty())
375 return false;
376
377 for (auto *tc: threads) {
378 if (!dynamic_cast<BaseKvmCPU *>(tc->getCpuPtr()))
379 return false;
380 }
381
382 return true;
383 #else
384 return false;
385 #endif
386 }
387
388 Addr
389 System::allocPhysPages(int npages)
390 {
391 Addr return_addr = pagePtr << PageShift;
392 pagePtr += npages;
393
394 Addr next_return_addr = pagePtr << PageShift;
395
396 if (_m5opRange.contains(next_return_addr)) {
397 warn("Reached m5ops MMIO region\n");
398 return_addr = 0xffffffff;
399 pagePtr = 0xffffffff >> PageShift;
400 }
401
402 if ((pagePtr << PageShift) > physmem.totalSize())
403 fatal("Out of memory, please increase size of physical memory.");
404 return return_addr;
405 }
406
407 Addr
408 System::memSize() const
409 {
410 return physmem.totalSize();
411 }
412
413 Addr
414 System::freeMemSize() const
415 {
416 return physmem.totalSize() - (pagePtr << PageShift);
417 }
418
419 bool
420 System::isMemAddr(Addr addr) const
421 {
422 return physmem.isMemAddr(addr);
423 }
424
425 void
426 System::addDeviceMemory(RequestorID requestor_id, AbstractMemory *deviceMemory)
427 {
428 if (!deviceMemMap.count(requestor_id)) {
429 deviceMemMap.insert(std::make_pair(requestor_id, deviceMemory));
430 }
431 }
432
433 bool
434 System::isDeviceMemAddr(PacketPtr pkt) const
435 {
436 const RequestorID& id = pkt->requestorId();
437
438 return (deviceMemMap.count(id) &&
439 deviceMemMap.at(id)->getAddrRange().contains(pkt->getAddr()));
440 }
441
442 AbstractMemory *
443 System::getDeviceMemory(RequestorID id) const
444 {
445 panic_if(!deviceMemMap.count(id),
446 "No device memory found for RequestorID %d\n", id);
447 return deviceMemMap.at(id);
448 }
449
450 void
451 System::drainResume()
452 {
453 totalNumInsts = 0;
454 }
455
456 void
457 System::serialize(CheckpointOut &cp) const
458 {
459 SERIALIZE_SCALAR(pagePtr);
460
461 for (auto &t: threads.threads) {
462 Tick when = 0;
463 if (t.resumeEvent && t.resumeEvent->scheduled())
464 when = t.resumeEvent->when();
465 ContextID id = t.context->contextId();
466 paramOut(cp, csprintf("quiesceEndTick_%d", id), when);
467 }
468
469 // also serialize the memories in the system
470 physmem.serializeSection(cp, "physmem");
471 }
472
473
474 void
475 System::unserialize(CheckpointIn &cp)
476 {
477 UNSERIALIZE_SCALAR(pagePtr);
478
479 for (auto &t: threads.threads) {
480 Tick when = 0;
481 ContextID id = t.context->contextId();
482 if (!optParamIn(cp, csprintf("quiesceEndTick_%d", id), when) ||
483 !when || !t.resumeEvent) {
484 continue;
485 }
486 # if THE_ISA != NULL_ISA
487 t.context->getCpuPtr()->schedule(t.resumeEvent, when);
488 # endif
489 }
490
491 // also unserialize the memories in the system
492 physmem.unserializeSection(cp, "physmem");
493 }
494
495 void
496 System::regStats()
497 {
498 SimObject::regStats();
499
500 for (uint32_t j = 0; j < numWorkIds ; j++) {
501 workItemStats[j] = new Stats::Histogram();
502 stringstream namestr;
503 ccprintf(namestr, "work_item_type%d", j);
504 workItemStats[j]->init(20)
505 .name(name() + "." + namestr.str())
506 .desc("Run time stat for" + namestr.str())
507 .prereq(*workItemStats[j]);
508 }
509 }
510
511 void
512 System::workItemEnd(uint32_t tid, uint32_t workid)
513 {
514 std::pair<uint32_t,uint32_t> p(tid, workid);
515 if (!lastWorkItemStarted.count(p))
516 return;
517
518 Tick samp = curTick() - lastWorkItemStarted[p];
519 DPRINTF(WorkItems, "Work item end: %d\t%d\t%lld\n", tid, workid, samp);
520
521 if (workid >= numWorkIds)
522 fatal("Got workid greater than specified in system configuration\n");
523
524 workItemStats[workid]->sample(samp);
525 lastWorkItemStarted.erase(p);
526 }
527
528 void
529 System::printSystems()
530 {
531 ios::fmtflags flags(cerr.flags());
532
533 vector<System *>::iterator i = systemList.begin();
534 vector<System *>::iterator end = systemList.end();
535 for (; i != end; ++i) {
536 System *sys = *i;
537 cerr << "System " << sys->name() << ": " << hex << sys << endl;
538 }
539
540 cerr.flags(flags);
541 }
542
543 void
544 printSystems()
545 {
546 System::printSystems();
547 }
548
549 std::string
550 System::stripSystemName(const std::string& requestor_name) const
551 {
552 if (startswith(requestor_name, name())) {
553 return requestor_name.substr(name().size());
554 } else {
555 return requestor_name;
556 }
557 }
558
559 RequestorID
560 System::lookupRequestorId(const SimObject* obj) const
561 {
562 RequestorID id = Request::invldRequestorId;
563
564 // number of occurrences of the SimObject pointer
565 // in the requestor list.
566 auto obj_number = 0;
567
568 for (int i = 0; i < requestors.size(); i++) {
569 if (requestors[i].obj == obj) {
570 id = i;
571 obj_number++;
572 }
573 }
574
575 fatal_if(obj_number > 1,
576 "Cannot lookup RequestorID by SimObject pointer: "
577 "More than one requestor is sharing the same SimObject\n");
578
579 return id;
580 }
581
582 RequestorID
583 System::lookupRequestorId(const std::string& requestor_name) const
584 {
585 std::string name = stripSystemName(requestor_name);
586
587 for (int i = 0; i < requestors.size(); i++) {
588 if (requestors[i].req_name == name) {
589 return i;
590 }
591 }
592
593 return Request::invldRequestorId;
594 }
595
596 RequestorID
597 System::getGlobalRequestorId(const std::string& requestor_name)
598 {
599 return _getRequestorId(nullptr, requestor_name);
600 }
601
602 RequestorID
603 System::getRequestorId(const SimObject* requestor, std::string subrequestor)
604 {
605 auto requestor_name = leafRequestorName(requestor, subrequestor);
606 return _getRequestorId(requestor, requestor_name);
607 }
608
609 RequestorID
610 System::_getRequestorId(const SimObject* requestor,
611 const std::string& requestor_name)
612 {
613 std::string name = stripSystemName(requestor_name);
614
615 // CPUs in switch_cpus ask for ids again after switching
616 for (int i = 0; i < requestors.size(); i++) {
617 if (requestors[i].req_name == name) {
618 return i;
619 }
620 }
621
622 // Verify that the statistics haven't been enabled yet
623 // Otherwise objects will have sized their stat buckets and
624 // they will be too small
625
626 if (Stats::enabled()) {
627 fatal("Can't request a requestorId after regStats(). "
628 "You must do so in init().\n");
629 }
630
631 // Generate a new RequestorID incrementally
632 RequestorID requestor_id = requestors.size();
633
634 // Append the new Requestor metadata to the group of system Requestors.
635 requestors.emplace_back(requestor, name, requestor_id);
636
637 return requestors.back().id;
638 }
639
640 std::string
641 System::leafRequestorName(const SimObject* requestor,
642 const std::string& subrequestor)
643 {
644 if (subrequestor.empty()) {
645 return requestor->name();
646 } else {
647 // Get the full requestor name by appending the subrequestor name to
648 // the root SimObject requestor name
649 return requestor->name() + "." + subrequestor;
650 }
651 }
652
653 std::string
654 System::getRequestorName(RequestorID requestor_id)
655 {
656 if (requestor_id >= requestors.size())
657 fatal("Invalid requestor_id passed to getRequestorName()\n");
658
659 const auto& requestor_info = requestors[requestor_id];
660 return requestor_info.req_name;
661 }
662
663 System *
664 SystemParams::create()
665 {
666 return new System(this);
667 }