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