gem5  v22.1.0.0
helpers.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016, 2022 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  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions are
16  * met: redistributions of source code must retain the above copyright
17  * notice, this list of conditions and the following disclaimer;
18  * redistributions in binary form must reproduce the above copyright
19  * notice, this list of conditions and the following disclaimer in the
20  * documentation and/or other materials provided with the distribution;
21  * neither the name of the copyright holders nor the names of its
22  * contributors may be used to endorse or promote products derived from
23  * this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 #include "kern/linux/helpers.hh"
39 
40 #include <type_traits>
41 
42 #include "base/compiler.hh"
44 #include "cpu/thread_context.hh"
45 #include "mem/port_proxy.hh"
47 #include "sim/byteswap.hh"
48 #include "sim/system.hh"
49 
50 namespace gem5 {
51 
52 namespace linux {
53 
54 namespace {
55 
56 namespace pre5_10 {
57 
59 struct GEM5_PACKED DmesgEntry
60 {
61  uint64_t ts_nsec;
62  uint16_t len;
63  uint16_t text_len;
64  uint16_t dict_len;
65  uint8_t facility;
66  uint8_t flags;
67 };
68 
70 static int
71 dumpDmesgEntry(const uint8_t *base, const uint8_t *end,
72  const ByteOrder bo,
73  std::ostream &os)
74 {
75  const size_t max_length = end - base;
76  DmesgEntry de;
77 
78  if (max_length < sizeof(de)) {
79  warn("Malformed dmesg entry\n");
80  return -1;
81  }
82 
83  memcpy(&de, base, sizeof(de));
84  de.ts_nsec = gtoh(de.ts_nsec, bo);
85  de.len = gtoh(de.len, bo);
86  de.text_len = gtoh(de.text_len, bo);
87 
88  if (de.len < sizeof(de) ||
89  max_length < de.len ||
90  max_length < sizeof(DmesgEntry) + de.text_len) {
91 
92  warn("Malformed dmesg entry:\n");
93  warn("\tMax length: %i\n", max_length);
94  warn("\tde.len: %i\n", de.len);
95  warn("\tde.text_len: %i\n", de.text_len);
96  return -1;
97  }
98 
99  ccprintf(os, "[%.6f] ", de.ts_nsec * 10e-9);
100  os.write((char *)base + sizeof(de), de.text_len);
101  os << std::endl;
102 
103  return de.len;
104 }
105 
107 void
108 dumpDmesg(ThreadContext *tc, std::ostream &os)
109 {
110  System *system = tc->getSystemPtr();
111  const ByteOrder bo = system->getGuestByteOrder();
112  const auto &symtab = system->workload->symtab(tc);
113  TranslatingPortProxy proxy(tc);
114 
115  auto lb = symtab.find("__log_buf");
116  auto lb_len = symtab.find("log_buf_len");
117  auto first = symtab.find("log_first_idx");
118  auto next = symtab.find("log_next_idx");
119 
120  auto end_it = symtab.end();
121 
122  if (lb == end_it || lb_len == end_it ||
123  first == end_it || next == end_it) {
124  warn("Failed to find kernel dmesg symbols.\n");
125  return;
126  }
127 
128  uint32_t log_buf_len = proxy.read<uint32_t>(lb_len->address, bo);
129  uint32_t log_first_idx = proxy.read<uint32_t>(first->address, bo);
130  uint32_t log_next_idx = proxy.read<uint32_t>(next->address, bo);
131 
132  if (log_first_idx >= log_buf_len || log_next_idx >= log_buf_len) {
133  warn("dmesg pointers/length corrupted\n");
134  return;
135  }
136 
137  // Normalize and read the dmesg ring buffer
138  std::vector<uint8_t> log_buf(log_buf_len);
139  int length;
140  if (log_first_idx < log_next_idx) {
141  length = log_next_idx - log_first_idx;
142  if (length < 0 || length > log_buf.size()) {
143  warn("Unexpected dmesg buffer length\n");
144  return;
145  }
146  proxy.readBlob(lb->address + log_first_idx, log_buf.data(), length);
147  } else {
148  const int length_2 = log_buf_len - log_first_idx;
149  if (length_2 < 0 || length_2 + log_next_idx > log_buf.size()) {
150  warn("Unexpected dmesg buffer length\n");
151  return;
152  }
153  length = log_buf_len;
154  proxy.readBlob(lb->address + log_first_idx, log_buf.data(), length_2);
155  proxy.readBlob(lb->address, log_buf.data() + length_2, log_next_idx);
156  }
157 
158  // Print dmesg buffer content
159  const uint8_t *cur = log_buf.data(), *end = log_buf.data() + length;
160  while (cur < end) {
161  int ret = dumpDmesgEntry(cur, end, bo, os);
162  if (ret < 0)
163  return;
164  cur += ret;
165  }
166 }
167 
168 } // namespace pre5_10
169 
170 namespace post5_10 {
171 
182 template<typename atomic_var_t>
183 struct GEM5_PACKED DmesgMetadataRecord
184 {
185  using guest_ptr_t = typename std::make_unsigned_t<atomic_var_t>;
186 
187  // Struct data members
188  atomic_var_t state;
189  struct
190  {
191  guest_ptr_t curr_offset;
192  guest_ptr_t next_offset;
194 
196  static DmesgMetadataRecord
197  read(const TranslatingPortProxy & proxy,
198  Addr address,
199  guest_ptr_t data_offset_mask,
200  const ByteOrder & bo)
201  {
202  DmesgMetadataRecord metadata;
203  proxy.readBlob(address, &metadata, sizeof(metadata));
204 
205  // Convert members to host byte order
206  metadata.state = gtoh(metadata.state, bo);
207  metadata.data_buffer.curr_offset =
208  gtoh(metadata.data_buffer.curr_offset, bo);
209  metadata.data_buffer.next_offset =
210  gtoh(metadata.data_buffer.next_offset, bo);
211 
212  // Mask the offsets
213  metadata.data_buffer.curr_offset =
214  metadata.data_buffer.curr_offset & data_offset_mask;
215  metadata.data_buffer.next_offset =
216  metadata.data_buffer.next_offset & data_offset_mask;
217 
218  return metadata;
219  }
220 };
221 
232 struct GEM5_PACKED DmesgInfoRecord
233 {
234  // Struct data members
235  uint64_t unused1;
236  uint64_t ts_nsec;
237  uint16_t message_size;
238  uint8_t unused2;
239  uint8_t unused3;
240  uint32_t unused4;
241  struct
242  {
243  char unused5_1[16];
244  char unused5_2[48];
246 
248  static DmesgInfoRecord
249  read(const TranslatingPortProxy & proxy,
250  Addr address,
251  const ByteOrder & bo)
252  {
253  DmesgInfoRecord info;
254  proxy.readBlob(address, &info, sizeof(info));
255 
256  // Convert members to host byte order
257  info.ts_nsec = gtoh(info.ts_nsec, bo);
258  info.message_size = gtoh(info.message_size, bo);
259 
260  return info;
261  }
262 };
263 
274 template<typename AtomicVarType>
275 struct GEM5_PACKED DmesgRingbuffer
276 {
277  static_assert(
278  std::disjunction<
279  std::is_same<AtomicVarType, int32_t>,
280  std::is_same<AtomicVarType, int64_t>
281  >::value,
282  "AtomicVarType must be int32_t or int64_t");
283 
284  using atomic_var_t = AtomicVarType;
285  using guest_ptr_t = typename std::make_unsigned_t<atomic_var_t>;
286  using metadata_record_t = DmesgMetadataRecord<atomic_var_t>;
287 
288  // Struct data members
289  struct
290  {
291  unsigned int mask_bits;
292  guest_ptr_t metadata_ring_ptr;
293  guest_ptr_t info_ring_ptr;
294  atomic_var_t unused1;
295  atomic_var_t unused2;
297  struct
298  {
299  unsigned int mask_bits;
300  guest_ptr_t data_ring_ptr;
301  atomic_var_t head_offset;
302  atomic_var_t tail_offset;
303  } data;
304  atomic_var_t fail;
305 
307  static DmesgRingbuffer
308  read(const TranslatingPortProxy & proxy,
309  const Addr address,
310  const ByteOrder & bo)
311  {
312  DmesgRingbuffer rb;
313  proxy.readBlob(address, &rb, sizeof(rb));
314 
315  // Convert members to host byte order
316  rb.metadata.mask_bits =
317  gtoh(rb.metadata.mask_bits, bo);
318  rb.metadata.metadata_ring_ptr =
319  gtoh(rb.metadata.metadata_ring_ptr, bo);
320  rb.metadata.info_ring_ptr =
321  gtoh(rb.metadata.info_ring_ptr, bo);
322 
323  rb.data.mask_bits = gtoh(rb.data.mask_bits, bo);
324  rb.data.data_ring_ptr = gtoh(rb.data.data_ring_ptr, bo);
325  rb.data.head_offset = gtoh(rb.data.head_offset, bo);
326  rb.data.tail_offset = gtoh(rb.data.tail_offset, bo);
327 
328  // Mask offsets to the correct number of bits
329  rb.data.head_offset =
330  rb.mask_data_offset(rb.data.head_offset);
331  rb.data.tail_offset =
332  rb.mask_data_offset(rb.data.tail_offset);
333 
334  return rb;
335  }
336 
340  template<typename as_type>
341  static as_type
342  make_offset_mask_as(const unsigned int mask_bits)
343  {
344  using unsigned_atomic_var_t =
346  const atomic_var_t offset_mask =
347  static_cast<atomic_var_t>(
348  (static_cast<unsigned_atomic_var_t>(1) << mask_bits) - 1);
349  return static_cast<as_type>(offset_mask);
350  }
351 
353  template<typename metadata_offset_t>
354  metadata_offset_t
355  make_metadata_offset_mask() const
356  {
357  return make_offset_mask_as<metadata_offset_t>(metadata.mask_bits);
358  }
359 
361  template<typename data_offset_t>
362  data_offset_t
363  make_data_offset_mask() const
364  {
365  return make_offset_mask_as<data_offset_t>(data.mask_bits);
366  }
367 
370  template<typename metadata_offset_t>
371  metadata_offset_t
372  mask_metadata_offset(const metadata_offset_t metadata_offset) const
373  {
374  const atomic_var_t MASK =
375  make_metadata_offset_mask<metadata_offset_t>();
376  return metadata_offset & MASK;
377  }
378 
380  template<typename data_offset_t>
381  data_offset_t
382  mask_data_offset(const data_offset_t data_offset) const
383  {
384  const atomic_var_t MASK = make_data_offset_mask<data_offset_t>();
385  return data_offset & MASK;
386  }
387 };
388 
389 // Aliases for the two types of Ringbuffer that could be used.
390 using Linux64_Ringbuffer = DmesgRingbuffer<int64_t>;
391 using Linux32_Ringbuffer = DmesgRingbuffer<int32_t>;
392 
406 template <typename ringbuffer_t,
407  typename atomic_var_t=typename ringbuffer_t::atomic_var_t,
408  typename guest_ptr_t=typename ringbuffer_t::guest_ptr_t>
409 atomic_var_t
410 iterateDataRingbuffer(std::ostream & os,
411  const TranslatingPortProxy & proxy,
412  const ringbuffer_t & rb,
413  const atomic_var_t offset,
414  const guest_ptr_t first_metadata_offset,
415  const ByteOrder bo)
416 {
417  using metadata_record_t = typename ringbuffer_t::metadata_record_t;
418 
419  constexpr size_t METADATA_RECORD_SIZE =
420  sizeof(typename ringbuffer_t::metadata_record_t);
421  constexpr size_t INFO_RECORD_SIZE = sizeof(DmesgInfoRecord);
422 
423  const guest_ptr_t DATA_OFFSET_MASK =
424  rb.template make_data_offset_mask<guest_ptr_t>();
425 
426  // Read the offset of the metadata record from the beginning of
427  // the data record.
428  guest_ptr_t metadata_info_offset = rb.mask_metadata_offset(
429  proxy.read<guest_ptr_t>(rb.data.data_ring_ptr + offset, bo));
430 
431  // If the metadata offset of the block is the same as the metadata
432  // offset of the first block of the data ringbuffer, then this
433  // data block is unsused (padding), and the iteration can wrap
434  // around to the beginning of the data ringbuffer (offset == 0).
435  if (metadata_info_offset == first_metadata_offset) {
436  return static_cast<atomic_var_t>(0);
437  }
438 
439  // Read the metadata record from the metadata ringbuffer.
440  guest_ptr_t metadata_address =
441  rb.metadata.metadata_ring_ptr +
442  (metadata_info_offset * METADATA_RECORD_SIZE);
443  metadata_record_t metadata =
444  metadata_record_t::read(proxy, metadata_address, DATA_OFFSET_MASK, bo);
445 
446  // Read the info record from the info ringbuffer.
447  guest_ptr_t info_address =
448  rb.metadata.info_ring_ptr +
449  (metadata_info_offset * INFO_RECORD_SIZE);
450  DmesgInfoRecord info =
451  DmesgInfoRecord::read(proxy, info_address, bo);
452 
453  // The metadata record should point back to the same data record
454  // in the data ringbuffer.
455  if (metadata.data_buffer.curr_offset != offset) {
456  warn_once("Dmesg dump: metadata record (at 0x%08x) does not point "
457  "back to the correponding data record (at 0x%08x). Dmesg "
458  "buffer may be corrupted",
459  metadata.data_buffer.next_offset, offset);
460  }
461 
462  // Read the message from the data record. This is placed
463  // immediately after the `guest_ptr_t` sized metadata offset at
464  // the beginning of the record.
465  std::vector<uint8_t> message(info.message_size);
466  proxy.readBlob(rb.data.data_ring_ptr + offset + sizeof(guest_ptr_t),
467  message.data(), info.message_size);
468 
469  // Print the record
470  ccprintf(os, "[%.6f] ", info.ts_nsec * 10e-9);
471  os.write((char *)message.data(), info.message_size);
472  os << "\n";
473 
474  // Return the offset of the next data record in the data
475  // ringbuffer.
476  return metadata.data_buffer.next_offset;
477 }
478 
483 template <typename ringbuffer_t>
484 void
485 dumpDmesgImpl(ThreadContext *tc, std::ostream &os)
486 {
487  using atomic_var_t = typename ringbuffer_t::atomic_var_t;
488  using guest_ptr_t = typename ringbuffer_t::guest_ptr_t;
489 
490  System *system = tc->getSystemPtr();
491  const ByteOrder bo = system->getGuestByteOrder();
492  const auto &symtab = system->workload->symtab(tc);
493  TranslatingPortProxy proxy(tc);
494 
495  auto symtab_end_it = symtab.end();
496 
497  // Read the dynamic ringbuffer structure from guest memory, if present.
498  ringbuffer_t dynamic_rb;
499  auto dynamic_rb_symbol = symtab.find("printk_rb_dynamic");
500  if (dynamic_rb_symbol != symtab_end_it) {
501  dynamic_rb = ringbuffer_t::read(proxy, dynamic_rb_symbol->address, bo);
502  } else {
503  warn("Failed to find required dmesg symbols.\n");
504  return;
505  }
506 
507  // Read the static ringbuffer structure from guest memory, if present.
508  ringbuffer_t static_rb;
509  auto static_rb_symbol = symtab.find("printk_rb_static");
510  if (static_rb_symbol != symtab_end_it) {
511  static_rb = ringbuffer_t::read(proxy, static_rb_symbol->address, bo);
512  } else {
513  warn("Failed to find required dmesg symbols.\n");
514  return;
515  }
516 
517  // Read the pointer to the active ringbuffer structure from guest
518  // memory. This should point to one of the two ringbuffer
519  // structures already read from guest memory.
520  guest_ptr_t active_ringbuffer_ptr = 0x0;
521  auto active_ringbuffer_ptr_symbol = symtab.find("prb");
522  if (active_ringbuffer_ptr_symbol != symtab_end_it) {
523  active_ringbuffer_ptr =
524  proxy.read<guest_ptr_t>(active_ringbuffer_ptr_symbol->address, bo);
525  } else {
526  warn("Failed to find required dmesg symbols.\n");
527  return;
528  }
529 
530  if (active_ringbuffer_ptr == 0 ||
531  (active_ringbuffer_ptr != dynamic_rb_symbol->address &&
532  active_ringbuffer_ptr != static_rb_symbol->address)) {
533  warn("Kernel Dmesg ringbuffer appears to be invalid.\n");
534  return;
535  }
536 
537  ringbuffer_t & rb =
538  (active_ringbuffer_ptr == dynamic_rb_symbol->address)
539  ? dynamic_rb : static_rb;
540 
541  atomic_var_t head_offset = rb.data.head_offset;
542  atomic_var_t tail_offset = rb.data.tail_offset;
543 
544  // Get some marker offsets into the data ringbuffer which will be
545  // used as end values to control the iteration.
546  const guest_ptr_t first_metadata_offset = rb.mask_metadata_offset(
547  proxy.read<guest_ptr_t>(rb.data.data_ring_ptr, bo));
548  const guest_ptr_t invalid_metadata_offset =
549  rb.template make_metadata_offset_mask<guest_ptr_t>() + 1;
550 
551  // Iterate over the active ringbuffer, printing each message to
552  // `os`. Use the maximum number of possible info records plus one
553  // (invalid_metadata_offset) as an escape counter to make sure the
554  // process doesn't iterate infinitely if the kernel data
555  // structures have been corrupted.
556 
557  // When head is behind tail, read to the end of the ringbuffer,
558  // then loop back to the begining.
559  //
560  // iterateDataRingbuffer will return offset at the beginning of
561  // the data ringbuffer when it loops back.
562  //
563  // `first_metadata_offset` is used to detect cases where the final data
564  // block is unused.
565  guest_ptr_t count = 0;
566  while (head_offset < tail_offset && count < invalid_metadata_offset) {
567  tail_offset =
568  iterateDataRingbuffer<ringbuffer_t>(
569  os, proxy, rb, tail_offset, first_metadata_offset, bo);
570  ++count;
571  }
572 
573  // When tail is behind head, read forwards from the tail offset to
574  // the head offset.
575  count = 0;
576  while (tail_offset < head_offset && count < invalid_metadata_offset) {
577  tail_offset =
578  iterateDataRingbuffer<ringbuffer_t>(
579  os, proxy, rb, tail_offset, invalid_metadata_offset, bo);
580  ++count;
581  }
582 }
583 
589 void
590 dumpDmesg(ThreadContext *tc, std::ostream &os)
591 {
592  System *system = tc->getSystemPtr();
593  const bool os_is_64_bit = loader::archIs64Bit(system->workload->getArch());
594 
595  if (os_is_64_bit) {
596  dumpDmesgImpl<Linux64_Ringbuffer>(tc, os);
597  } else {
598  dumpDmesgImpl<Linux32_Ringbuffer>(tc, os);
599  }
600 }
601 
602 } // namespace post5_10
603 
604 } // anonymous namespace
605 
606 void
607 dumpDmesg(ThreadContext *tc, std::ostream &os)
608 {
609  System *system = tc->getSystemPtr();
610  const auto &symtab = system->workload->symtab(tc);
611 
612  auto end_it = symtab.end();
613 
614  // Search for symbols associated with the Kernel Dmesg ringbuffer,
615  // pre-v5.10.
616  auto lb = symtab.find("__log_buf");
617  auto lb_len = symtab.find("log_buf_len");
618  auto first = symtab.find("log_first_idx");
619  auto next = symtab.find("log_next_idx");
620 
621  if (lb != end_it && lb_len != end_it &&
622  first != end_it && next != end_it) {
624  return;
625  }
626 
627  // Search for symbols associated with the Kernel Dmesg ringbuffer,
628  // post-v5.10.
629  auto printk_rb_static = symtab.find("printk_rb_static");
630  auto printk_rb_dynamic = symtab.find("printk_rb_dynamic");
631 
632  if (printk_rb_dynamic != end_it || printk_rb_static != end_it) {
634  return;
635  }
636 
637  // Required symbols relating to the Kernel Dmesg buffer were not
638  // found for any supported version of Linux.
639  warn("Failed to find kernel dmesg symbols.\n");
640 }
641 
642 } // namespace linux
643 
644 } // namespace gem5
ThreadContext is the external interface to all thread state for anything outside of the CPU.
virtual System * getSystemPtr()=0
uint64_t ts_nsec
Definition: helpers.cc:61
uint32_t unused4
Definition: helpers.cc:240
struct gem5::linux::@1364::post5_10::DmesgRingbuffer::@334 metadata
uint64_t unused1
Definition: helpers.cc:235
uint8_t facility
Definition: helpers.cc:65
uint8_t unused3
Definition: helpers.cc:239
unsigned int mask_bits
Definition: helpers.cc:291
atomic_var_t state
Definition: helpers.cc:188
char unused5_1[16]
Definition: helpers.cc:243
atomic_var_t head_offset
Definition: helpers.cc:301
guest_ptr_t next_offset
Definition: helpers.cc:192
uint16_t message_size
Definition: helpers.cc:237
guest_ptr_t curr_offset
Definition: helpers.cc:191
uint16_t len
Definition: helpers.cc:62
uint8_t unused2
Definition: helpers.cc:238
uint8_t flags
Definition: helpers.cc:66
struct gem5::linux::@1364::post5_10::DmesgInfoRecord::@333 unused5
uint16_t dict_len
Definition: helpers.cc:64
guest_ptr_t metadata_ring_ptr
Definition: helpers.cc:292
guest_ptr_t info_ring_ptr
Definition: helpers.cc:293
atomic_var_t tail_offset
Definition: helpers.cc:302
struct gem5::linux::@1364::post5_10::DmesgRingbuffer::@335 data
struct gem5::linux::@1364::post5_10::DmesgMetadataRecord::@332 data_buffer
char unused5_2[48]
Definition: helpers.cc:244
guest_ptr_t data_ring_ptr
Definition: helpers.cc:300
atomic_var_t fail
Definition: helpers.cc:304
uint16_t text_len
Definition: helpers.cc:63
#define warn(...)
Definition: logging.hh:246
#define warn_once(...)
Definition: logging.hh:250
Bitfield< 23, 0 > offset
Definition: types.hh:144
Bitfield< 9 > e
Definition: misc_types.hh:65
Bitfield< 25, 21 > bo
Definition: types.hh:82
Bitfield< 15 > system
Definition: misc.hh:1004
Bitfield< 51, 12 > base
Definition: pagetable.hh:141
Bitfield< 17 > os
Definition: misc.hh:810
Bitfield< 3 > de
Definition: misc.hh:642
void dumpDmesg(ThreadContext *tc, std::ostream &os)
Dump Linux's dmesg log buffer to the an output stream.
Definition: helpers.cc:607
bool archIs64Bit(const loader::Arch arch)
Determine whether the loader::Arch is 64-bit or 32-bit.
Definition: object_file.cc:152
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
T gtoh(T value, ByteOrder guest_byte_order)
Definition: byteswap.hh:194
void ccprintf(cp::Print &print)
Definition: cprintf.hh:130
PortProxy Object Declaration.
PM4 packets.
Definition: pm4_defines.hh:78

Generated on Wed Dec 21 2022 10:22:36 for gem5 by doxygen 1.9.1