base, sim, mem, arch: Remove the dummy CPU in NULL
[gem5.git] / src / sim / system.hh
1 /*
2 * Copyright (c) 2012, 2014, 2018 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) 2002-2005 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 #ifndef __SYSTEM_HH__
43 #define __SYSTEM_HH__
44
45 #include <string>
46 #include <unordered_map>
47 #include <utility>
48 #include <vector>
49
50 #include "arch/isa_traits.hh"
51 #include "base/loader/memory_image.hh"
52 #include "base/loader/symtab.hh"
53 #include "base/statistics.hh"
54 #include "config/the_isa.hh"
55 #include "cpu/pc_event.hh"
56 #include "enums/MemoryMode.hh"
57 #include "mem/mem_requestor.hh"
58 #include "mem/physical.hh"
59 #include "mem/port.hh"
60 #include "mem/port_proxy.hh"
61 #include "params/System.hh"
62 #include "sim/futex_map.hh"
63 #include "sim/redirect_path.hh"
64 #include "sim/se_signal.hh"
65 #include "sim/sim_object.hh"
66 #include "sim/workload.hh"
67
68 class BaseRemoteGDB;
69 class KvmVM;
70 class ThreadContext;
71
72 class System : public SimObject, public PCEventScope
73 {
74 private:
75
76 /**
77 * Private class for the system port which is only used as a
78 * requestor for debug access and for non-structural entities that do
79 * not have a port of their own.
80 */
81 class SystemPort : public RequestPort
82 {
83 public:
84
85 /**
86 * Create a system port with a name and an owner.
87 */
88 SystemPort(const std::string &_name, SimObject *_owner)
89 : RequestPort(_name, _owner)
90 { }
91 bool recvTimingResp(PacketPtr pkt) override
92 { panic("SystemPort does not receive timing!\n"); return false; }
93 void recvReqRetry() override
94 { panic("SystemPort does not expect retry!\n"); }
95 };
96
97 std::list<PCEvent *> liveEvents;
98 SystemPort _systemPort;
99
100 // Map of memory address ranges for devices with their own backing stores
101 std::unordered_map<RequestorID, AbstractMemory *> deviceMemMap;
102
103 public:
104
105 class Threads
106 {
107 private:
108 struct Thread
109 {
110 ThreadContext *context = nullptr;
111 bool active = false;
112 BaseRemoteGDB *gdb = nullptr;
113 Event *resumeEvent = nullptr;
114
115 void resume();
116 std::string name() const;
117 void quiesce() const;
118 };
119
120 std::vector<Thread> threads;
121
122 Thread &
123 thread(ContextID id)
124 {
125 assert(id < size());
126 return threads[id];
127 }
128
129 const Thread &
130 thread(ContextID id) const
131 {
132 assert(id < size());
133 return threads[id];
134 }
135
136 ContextID insert(ThreadContext *tc, ContextID id=InvalidContextID);
137 void replace(ThreadContext *tc, ContextID id);
138
139 friend class System;
140
141 public:
142 class const_iterator
143 {
144 private:
145 const Threads &threads;
146 int pos;
147
148 friend class Threads;
149
150 const_iterator(const Threads &_threads, int _pos) :
151 threads(_threads), pos(_pos)
152 {}
153
154 public:
155 const_iterator(const const_iterator &) = default;
156 const_iterator &operator = (const const_iterator &) = default;
157
158 using iterator_category = std::forward_iterator_tag;
159 using value_type = ThreadContext *;
160 using difference_type = int;
161 using pointer = const value_type *;
162 using reference = const value_type &;
163
164 const_iterator &
165 operator ++ ()
166 {
167 pos++;
168 return *this;
169 }
170
171 const_iterator
172 operator ++ (int)
173 {
174 return const_iterator(threads, pos++);
175 }
176
177 reference operator * () { return threads.thread(pos).context; }
178 pointer operator -> () { return &threads.thread(pos).context; }
179
180 bool
181 operator == (const const_iterator &other) const
182 {
183 return &threads == &other.threads && pos == other.pos;
184 }
185
186 bool
187 operator != (const const_iterator &other) const
188 {
189 return !(*this == other);
190 }
191 };
192
193 ThreadContext *findFree();
194
195 ThreadContext *
196 operator [](ContextID id) const
197 {
198 return thread(id).context;
199 }
200
201 void markActive(ContextID id) { thread(id).active = true; }
202
203 int size() const { return threads.size(); }
204 bool empty() const { return threads.empty(); }
205 int numRunning() const;
206 int
207 numActive() const
208 {
209 int count = 0;
210 for (auto &thread: threads) {
211 if (thread.active)
212 count++;
213 }
214 return count;
215 }
216
217 void quiesce(ContextID id);
218 void quiesceTick(ContextID id, Tick when);
219
220 const_iterator begin() const { return const_iterator(*this, 0); }
221 const_iterator end() const { return const_iterator(*this, size()); }
222 };
223
224 /**
225 * After all objects have been created and all ports are
226 * connected, check that the system port is connected.
227 */
228 void init() override;
229 void startup() override;
230
231 /**
232 * Get a reference to the system port that can be used by
233 * non-structural simulation objects like processes or threads, or
234 * external entities like loaders and debuggers, etc, to access
235 * the memory system.
236 *
237 * @return a reference to the system port we own
238 */
239 RequestPort& getSystemPort() { return _systemPort; }
240
241 /**
242 * Additional function to return the Port of a memory object.
243 */
244 Port &getPort(const std::string &if_name,
245 PortID idx=InvalidPortID) override;
246
247 /** @{ */
248 /**
249 * Is the system in atomic mode?
250 *
251 * There are currently two different atomic memory modes:
252 * 'atomic', which supports caches; and 'atomic_noncaching', which
253 * bypasses caches. The latter is used by hardware virtualized
254 * CPUs. SimObjects are expected to use Port::sendAtomic() and
255 * Port::recvAtomic() when accessing memory in this mode.
256 */
257 bool isAtomicMode() const {
258 return memoryMode == Enums::atomic ||
259 memoryMode == Enums::atomic_noncaching;
260 }
261
262 /**
263 * Is the system in timing mode?
264 *
265 * SimObjects are expected to use Port::sendTiming() and
266 * Port::recvTiming() when accessing memory in this mode.
267 */
268 bool isTimingMode() const {
269 return memoryMode == Enums::timing;
270 }
271
272 /**
273 * Should caches be bypassed?
274 *
275 * Some CPUs need to bypass caches to allow direct memory
276 * accesses, which is required for hardware virtualization.
277 */
278 bool bypassCaches() const {
279 return memoryMode == Enums::atomic_noncaching;
280 }
281 /** @} */
282
283 /** @{ */
284 /**
285 * Get the memory mode of the system.
286 *
287 * \warn This should only be used by the Python world. The C++
288 * world should use one of the query functions above
289 * (isAtomicMode(), isTimingMode(), bypassCaches()).
290 */
291 Enums::MemoryMode getMemoryMode() const { return memoryMode; }
292
293 /**
294 * Change the memory mode of the system.
295 *
296 * \warn This should only be called by the Python!
297 *
298 * @param mode Mode to change to (atomic/timing/...)
299 */
300 void setMemoryMode(Enums::MemoryMode mode);
301 /** @} */
302
303 /**
304 * Get the cache line size of the system.
305 */
306 unsigned int cacheLineSize() const { return _cacheLineSize; }
307
308 Threads threads;
309
310 const bool multiThread;
311
312 using SimObject::schedule;
313
314 bool schedule(PCEvent *event) override;
315 bool remove(PCEvent *event) override;
316
317 Addr pagePtr;
318
319 uint64_t init_param;
320
321 /** Port to physical memory used for writing object files into ram at
322 * boot.*/
323 PortProxy physProxy;
324
325 /** OS kernel */
326 Workload *workload = nullptr;
327
328 public:
329 /**
330 * Get a pointer to the Kernel Virtual Machine (KVM) SimObject,
331 * if present.
332 */
333 KvmVM* getKvmVM() {
334 return kvmVM;
335 }
336
337 /** Verify gem5 configuration will support KVM emulation */
338 bool validKvmEnvironment() const;
339
340 /** Get a pointer to access the physical memory of the system */
341 PhysicalMemory& getPhysMem() { return physmem; }
342
343 /** Amount of physical memory that is still free */
344 Addr freeMemSize() const;
345
346 /** Amount of physical memory that exists */
347 Addr memSize() const;
348
349 /**
350 * Check if a physical address is within a range of a memory that
351 * is part of the global address map.
352 *
353 * @param addr A physical address
354 * @return Whether the address corresponds to a memory
355 */
356 bool isMemAddr(Addr addr) const;
357
358 /**
359 * Add a physical memory range for a device. The ranges added here will
360 * be considered a non-PIO memory address if the requestorId of the packet
361 * and range match something in the device memory map.
362 */
363 void addDeviceMemory(RequestorID requestorId,
364 AbstractMemory *deviceMemory);
365
366 /**
367 * Similar to isMemAddr but for devices. Checks if a physical address
368 * of the packet match an address range of a device corresponding to the
369 * RequestorId of the request.
370 */
371 bool isDeviceMemAddr(PacketPtr pkt) const;
372
373 /**
374 * Return a pointer to the device memory.
375 */
376 AbstractMemory *getDeviceMemory(RequestorID _id) const;
377
378 /**
379 * Get the architecture.
380 */
381 Arch getArch() const { return Arch::TheISA; }
382
383 /**
384 * Get the guest byte order.
385 */
386 ByteOrder
387 getGuestByteOrder() const
388 {
389 return _params->byte_order;
390 }
391
392 /**
393 * Get the page bytes for the ISA.
394 */
395 Addr getPageBytes() const { return TheISA::PageBytes; }
396
397 /**
398 * Get the number of bits worth of in-page address for the ISA.
399 */
400 Addr getPageShift() const { return TheISA::PageShift; }
401
402 /**
403 * The thermal model used for this system (if any).
404 */
405 ThermalModel * getThermalModel() const { return thermalModel; }
406
407 protected:
408
409 KvmVM *const kvmVM;
410
411 PhysicalMemory physmem;
412
413 Enums::MemoryMode memoryMode;
414
415 const unsigned int _cacheLineSize;
416
417 uint64_t workItemsBegin;
418 uint64_t workItemsEnd;
419 uint32_t numWorkIds;
420
421 /** This array is a per-system list of all devices capable of issuing a
422 * memory system request and an associated string for each requestor id.
423 * It's used to uniquely id any requestor in the system by name for things
424 * like cache statistics.
425 */
426 std::vector<RequestorInfo> requestors;
427
428 ThermalModel * thermalModel;
429
430 protected:
431 /**
432 * Strips off the system name from a requestor name
433 */
434 std::string stripSystemName(const std::string& requestor_name) const;
435
436 public:
437
438 /**
439 * Request an id used to create a request object in the system. All objects
440 * that intend to issues requests into the memory system must request an id
441 * in the init() phase of startup. All requestor ids must be fixed by the
442 * regStats() phase that immediately precedes it. This allows objects in
443 * the memory system to understand how many requestors may exist and
444 * appropriately name the bins of their per-requestor stats before the
445 * stats are finalized.
446 *
447 * Registers a RequestorID:
448 * This method takes two parameters, one of which is optional.
449 * The first one is the requestor object, and it is compulsory; in case
450 * a object has multiple (sub)requestors, a second parameter must be
451 * provided and it contains the name of the subrequestor. The method will
452 * create a requestor's name by concatenating the SimObject name with the
453 * eventual subrequestor string, separated by a dot.
454 *
455 * As an example:
456 * For a cpu having two requestors: a data requestor and an
457 * instruction requestor,
458 * the method must be called twice:
459 *
460 * instRequestorId = getRequestorId(cpu, "inst");
461 * dataRequestorId = getRequestorId(cpu, "data");
462 *
463 * and the requestors' names will be:
464 * - "cpu.inst"
465 * - "cpu.data"
466 *
467 * @param requestor SimObject related to the requestor
468 * @param subrequestor String containing the subrequestor's name
469 * @return the requestor's ID.
470 */
471 RequestorID getRequestorId(const SimObject* requestor,
472 std::string subrequestor = std::string());
473
474 /**
475 * Registers a GLOBAL RequestorID, which is a RequestorID not related
476 * to any particular SimObject; since no SimObject is passed,
477 * the requestor gets registered by providing the full requestor name.
478 *
479 * @param requestorName full name of the requestor
480 * @return the requestor's ID.
481 */
482 RequestorID getGlobalRequestorId(const std::string& requestor_name);
483
484 /**
485 * Get the name of an object for a given request id.
486 */
487 std::string getRequestorName(RequestorID requestor_id);
488
489 /**
490 * Looks up the RequestorID for a given SimObject
491 * returns an invalid RequestorID (invldRequestorId) if not found.
492 */
493 RequestorID lookupRequestorId(const SimObject* obj) const;
494
495 /**
496 * Looks up the RequestorID for a given object name string
497 * returns an invalid RequestorID (invldRequestorId) if not found.
498 */
499 RequestorID lookupRequestorId(const std::string& name) const;
500
501 /** Get the number of requestors registered in the system */
502 RequestorID maxRequestors() { return requestors.size(); }
503
504 protected:
505 /** helper function for getRequestorId */
506 RequestorID _getRequestorId(const SimObject* requestor,
507 const std::string& requestor_name);
508
509 /**
510 * Helper function for constructing the full (sub)requestor name
511 * by providing the root requestor and the relative subrequestor name.
512 */
513 std::string leafRequestorName(const SimObject* requestor,
514 const std::string& subrequestor);
515
516 public:
517
518 void regStats() override;
519 /**
520 * Called by pseudo_inst to track the number of work items started by this
521 * system.
522 */
523 uint64_t
524 incWorkItemsBegin()
525 {
526 return ++workItemsBegin;
527 }
528
529 /**
530 * Called by pseudo_inst to track the number of work items completed by
531 * this system.
532 */
533 uint64_t
534 incWorkItemsEnd()
535 {
536 return ++workItemsEnd;
537 }
538
539 /**
540 * Called by pseudo_inst to mark the cpus actively executing work items.
541 * Returns the total number of cpus that have executed work item begin or
542 * ends.
543 */
544 int
545 markWorkItem(int index)
546 {
547 threads.markActive(index);
548 return threads.numActive();
549 }
550
551 inline void workItemBegin(uint32_t tid, uint32_t workid)
552 {
553 std::pair<uint32_t,uint32_t> p(tid, workid);
554 lastWorkItemStarted[p] = curTick();
555 }
556
557 void workItemEnd(uint32_t tid, uint32_t workid);
558
559 public:
560 bool breakpoint();
561
562 public:
563 typedef SystemParams Params;
564
565 protected:
566 Params *_params;
567
568 /**
569 * Range for memory-mapped m5 pseudo ops. The range will be
570 * invalid/empty if disabled.
571 */
572 const AddrRange _m5opRange;
573
574 public:
575 System(Params *p);
576 ~System();
577
578 const Params *params() const { return (const Params *)_params; }
579
580 /**
581 * Range used by memory-mapped m5 pseudo-ops if enabled. Returns
582 * an invalid/empty range if disabled.
583 */
584 const AddrRange &m5opRange() const { return _m5opRange; }
585
586 public:
587
588 /// Allocate npages contiguous unused physical pages
589 /// @return Starting address of first page
590 Addr allocPhysPages(int npages);
591
592 ContextID registerThreadContext(
593 ThreadContext *tc, ContextID assigned=InvalidContextID);
594 void replaceThreadContext(ThreadContext *tc, ContextID context_id);
595
596 void serialize(CheckpointOut &cp) const override;
597 void unserialize(CheckpointIn &cp) override;
598
599 void drainResume() override;
600
601 public:
602 Counter totalNumInsts;
603 std::map<std::pair<uint32_t,uint32_t>, Tick> lastWorkItemStarted;
604 std::map<uint32_t, Stats::Histogram*> workItemStats;
605
606 ////////////////////////////////////////////
607 //
608 // STATIC GLOBAL SYSTEM LIST
609 //
610 ////////////////////////////////////////////
611
612 static std::vector<System *> systemList;
613 static int numSystemsRunning;
614
615 static void printSystems();
616
617 FutexMap futexMap;
618
619 static const int maxPID = 32768;
620
621 /** Process set to track which PIDs have already been allocated */
622 std::set<int> PIDs;
623
624 // By convention, all signals are owned by the receiving process. The
625 // receiver will delete the signal upon reception.
626 std::list<BasicSignal> signalList;
627
628 // Used by syscall-emulation mode. This member contains paths which need
629 // to be redirected to the faux-filesystem (a duplicate filesystem
630 // intended to replace certain files on the host filesystem).
631 std::vector<RedirectPath*> redirectPaths;
632 };
633
634 void printSystems();
635
636 #endif // __SYSTEM_HH__