gem5  v21.1.0.2
physical.cc
Go to the documentation of this file.
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  * 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 "mem/physical.hh"
39 
40 #include <fcntl.h>
41 #include <sys/mman.h>
42 #include <sys/types.h>
43 #include <sys/user.h>
44 #include <unistd.h>
45 #include <zlib.h>
46 
47 #include <cerrno>
48 #include <climits>
49 #include <cstdio>
50 #include <iostream>
51 #include <string>
52 
53 #include "base/trace.hh"
54 #include "debug/AddrRanges.hh"
55 #include "debug/Checkpoint.hh"
56 #include "mem/abstract_mem.hh"
57 #include "sim/serialize.hh"
58 
65 #if defined(__APPLE__) || defined(__FreeBSD__)
66 #ifndef MAP_NORESERVE
67 #define MAP_NORESERVE 0
68 #endif
69 #endif
70 
71 namespace gem5
72 {
73 
74 namespace memory
75 {
76 
77 PhysicalMemory::PhysicalMemory(const std::string& _name,
78  const std::vector<AbstractMemory*>& _memories,
79  bool mmap_using_noreserve,
80  const std::string& shared_backstore) :
81  _name(_name), size(0), mmapUsingNoReserve(mmap_using_noreserve),
82  sharedBackstore(shared_backstore)
83 {
84  if (mmap_using_noreserve)
85  warn("Not reserving swap space. May cause SIGSEGV on actual usage\n");
86 
87  // add the memories from the system to the address map as
88  // appropriate
89  for (const auto& m : _memories) {
90  // only add the memory if it is part of the global address map
91  if (m->isInAddrMap()) {
92  memories.push_back(m);
93 
94  // calculate the total size once and for all
95  size += m->size();
96 
97  // add the range to our interval tree and make sure it does not
98  // intersect an existing range
99  fatal_if(addrMap.insert(m->getAddrRange(), m) == addrMap.end(),
100  "Memory address range for %s is overlapping\n",
101  m->name());
102  } else {
103  // this type of memory is used e.g. as reference memory by
104  // Ruby, and they also needs a backing store, but should
105  // not be part of the global address map
106  DPRINTF(AddrRanges,
107  "Skipping memory %s that is not in global address map\n",
108  m->name());
109 
110  // sanity check
111  fatal_if(m->getAddrRange().interleaved(),
112  "Memory %s that is not in the global address map cannot "
113  "be interleaved\n", m->name());
114 
115  // simply do it independently, also note that this kind of
116  // memories are allowed to overlap in the logic address
117  // map
118  std::vector<AbstractMemory*> unmapped_mems{m};
119  createBackingStore(m->getAddrRange(), unmapped_mems,
120  m->isConfReported(), m->isInAddrMap(),
121  m->isKvmMap());
122  }
123  }
124 
125  // iterate over the increasing addresses and chunks of contiguous
126  // space to be mapped to backing store, create it and inform the
127  // memories
128  std::vector<AddrRange> intlv_ranges;
129  std::vector<AbstractMemory*> curr_memories;
130  for (const auto& r : addrMap) {
131  // simply skip past all memories that are null and hence do
132  // not need any backing store
133  if (!r.second->isNull()) {
134  // if the range is interleaved then save it for now
135  if (r.first.interleaved()) {
136  // if we already got interleaved ranges that are not
137  // part of the same range, then first do a merge
138  // before we add the new one
139  if (!intlv_ranges.empty() &&
140  !intlv_ranges.back().mergesWith(r.first)) {
141  AddrRange merged_range(intlv_ranges);
142 
143  AbstractMemory *f = curr_memories.front();
144  for (const auto& c : curr_memories)
145  if (f->isConfReported() != c->isConfReported() ||
146  f->isInAddrMap() != c->isInAddrMap() ||
147  f->isKvmMap() != c->isKvmMap())
148  fatal("Inconsistent flags in an interleaved "
149  "range\n");
150 
151  createBackingStore(merged_range, curr_memories,
152  f->isConfReported(), f->isInAddrMap(),
153  f->isKvmMap());
154 
155  intlv_ranges.clear();
156  curr_memories.clear();
157  }
158  intlv_ranges.push_back(r.first);
159  curr_memories.push_back(r.second);
160  } else {
161  std::vector<AbstractMemory*> single_memory{r.second};
162  createBackingStore(r.first, single_memory,
163  r.second->isConfReported(),
164  r.second->isInAddrMap(),
165  r.second->isKvmMap());
166  }
167  }
168  }
169 
170  // if there is still interleaved ranges waiting to be merged, go
171  // ahead and do it
172  if (!intlv_ranges.empty()) {
173  AddrRange merged_range(intlv_ranges);
174 
175  AbstractMemory *f = curr_memories.front();
176  for (const auto& c : curr_memories)
177  if (f->isConfReported() != c->isConfReported() ||
178  f->isInAddrMap() != c->isInAddrMap() ||
179  f->isKvmMap() != c->isKvmMap())
180  fatal("Inconsistent flags in an interleaved "
181  "range\n");
182 
183  createBackingStore(merged_range, curr_memories,
184  f->isConfReported(), f->isInAddrMap(),
185  f->isKvmMap());
186  }
187 }
188 
189 void
191  AddrRange range, const std::vector<AbstractMemory*>& _memories,
192  bool conf_table_reported, bool in_addr_map, bool kvm_map)
193 {
194  panic_if(range.interleaved(),
195  "Cannot create backing store for interleaved range %s\n",
196  range.to_string());
197 
198  // perform the actual mmap
199  DPRINTF(AddrRanges, "Creating backing store for range %s with size %d\n",
200  range.to_string(), range.size());
201 
202  int shm_fd;
203  int map_flags;
204 
205  if (sharedBackstore.empty()) {
206  shm_fd = -1;
207  map_flags = MAP_ANON | MAP_PRIVATE;
208  } else {
209  DPRINTF(AddrRanges, "Sharing backing store as %s\n",
210  sharedBackstore.c_str());
211  shm_fd = shm_open(sharedBackstore.c_str(), O_CREAT | O_RDWR, 0666);
212  if (shm_fd == -1)
213  panic("Shared memory failed");
214  if (ftruncate(shm_fd, range.size()))
215  panic("Setting size of shared memory failed");
216  map_flags = MAP_SHARED;
217  }
218 
219  // to be able to simulate very large memories, the user can opt to
220  // pass noreserve to mmap
221  if (mmapUsingNoReserve) {
222  map_flags |= MAP_NORESERVE;
223  }
224 
225  uint8_t* pmem = (uint8_t*) mmap(NULL, range.size(),
226  PROT_READ | PROT_WRITE,
227  map_flags, shm_fd, 0);
228 
229  if (pmem == (uint8_t*) MAP_FAILED) {
230  perror("mmap");
231  fatal("Could not mmap %d bytes for range %s!\n", range.size(),
232  range.to_string());
233  }
234 
235  // remember this backing store so we can checkpoint it and unmap
236  // it appropriately
237  backingStore.emplace_back(range, pmem,
238  conf_table_reported, in_addr_map, kvm_map);
239 
240  // point the memories to their backing store
241  for (const auto& m : _memories) {
242  DPRINTF(AddrRanges, "Mapping memory %s to backing store\n",
243  m->name());
244  m->setBackingStore(pmem);
245  }
246 }
247 
249 {
250  // unmap the backing store
251  for (auto& s : backingStore)
252  munmap((char*)s.pmem, s.range.size());
253 }
254 
255 bool
257 {
258  return addrMap.contains(addr) != addrMap.end();
259 }
260 
263 {
264  // this could be done once in the constructor, but since it is unlikely to
265  // be called more than once the iteration should not be a problem
266  AddrRangeList ranges;
267  std::vector<AddrRange> intlv_ranges;
268  for (const auto& r : addrMap) {
269  if (r.second->isConfReported()) {
270  // if the range is interleaved then save it for now
271  if (r.first.interleaved()) {
272  // if we already got interleaved ranges that are not
273  // part of the same range, then first do a merge
274  // before we add the new one
275  if (!intlv_ranges.empty() &&
276  !intlv_ranges.back().mergesWith(r.first)) {
277  ranges.push_back(AddrRange(intlv_ranges));
278  intlv_ranges.clear();
279  }
280  intlv_ranges.push_back(r.first);
281  } else {
282  // keep the current range
283  ranges.push_back(r.first);
284  }
285  }
286  }
287 
288  // if there is still interleaved ranges waiting to be merged,
289  // go ahead and do it
290  if (!intlv_ranges.empty()) {
291  ranges.push_back(AddrRange(intlv_ranges));
292  }
293 
294  return ranges;
295 }
296 
297 void
299 {
300  assert(pkt->isRequest());
301  const auto& m = addrMap.contains(pkt->getAddrRange());
302  assert(m != addrMap.end());
303  m->second->access(pkt);
304 }
305 
306 void
308 {
309  assert(pkt->isRequest());
310  const auto& m = addrMap.contains(pkt->getAddrRange());
311  assert(m != addrMap.end());
312  m->second->functionalAccess(pkt);
313 }
314 
315 void
317 {
318  // serialize all the locked addresses and their context ids
319  std::vector<Addr> lal_addr;
320  std::vector<ContextID> lal_cid;
321 
322  for (auto& m : memories) {
323  const std::list<LockedAddr>& locked_addrs = m->getLockedAddrList();
324  for (const auto& l : locked_addrs) {
325  lal_addr.push_back(l.addr);
326  lal_cid.push_back(l.contextId);
327  }
328  }
329 
330  SERIALIZE_CONTAINER(lal_addr);
331  SERIALIZE_CONTAINER(lal_cid);
332 
333  // serialize the backing stores
334  unsigned int nbr_of_stores = backingStore.size();
335  SERIALIZE_SCALAR(nbr_of_stores);
336 
337  unsigned int store_id = 0;
338  // store each backing store memory segment in a file
339  for (auto& s : backingStore) {
340  ScopedCheckpointSection sec(cp, csprintf("store%d", store_id));
341  serializeStore(cp, store_id++, s.range, s.pmem);
342  }
343 }
344 
345 void
347  AddrRange range, uint8_t* pmem) const
348 {
349  // we cannot use the address range for the name as the
350  // memories that are not part of the address map can overlap
351  std::string filename =
352  name() + ".store" + std::to_string(store_id) + ".pmem";
353  long range_size = range.size();
354 
355  DPRINTF(Checkpoint, "Serializing physical memory %s with size %d\n",
356  filename, range_size);
357 
358  SERIALIZE_SCALAR(store_id);
359  SERIALIZE_SCALAR(filename);
360  SERIALIZE_SCALAR(range_size);
361 
362  // write memory file
363  std::string filepath = CheckpointIn::dir() + "/" + filename.c_str();
364  gzFile compressed_mem = gzopen(filepath.c_str(), "wb");
365  if (compressed_mem == NULL)
366  fatal("Can't open physical memory checkpoint file '%s'\n",
367  filename);
368 
369  uint64_t pass_size = 0;
370 
371  // gzwrite fails if (int)len < 0 (gzwrite returns int)
372  for (uint64_t written = 0; written < range.size();
373  written += pass_size) {
374  pass_size = (uint64_t)INT_MAX < (range.size() - written) ?
375  (uint64_t)INT_MAX : (range.size() - written);
376 
377  if (gzwrite(compressed_mem, pmem + written,
378  (unsigned int) pass_size) != (int) pass_size) {
379  fatal("Write failed on physical memory checkpoint file '%s'\n",
380  filename);
381  }
382  }
383 
384  // close the compressed stream and check that the exit status
385  // is zero
386  if (gzclose(compressed_mem))
387  fatal("Close failed on physical memory checkpoint file '%s'\n",
388  filename);
389 
390 }
391 
392 void
394 {
395  // unserialize the locked addresses and map them to the
396  // appropriate memory controller
397  std::vector<Addr> lal_addr;
398  std::vector<ContextID> lal_cid;
399  UNSERIALIZE_CONTAINER(lal_addr);
400  UNSERIALIZE_CONTAINER(lal_cid);
401  for (size_t i = 0; i < lal_addr.size(); ++i) {
402  const auto& m = addrMap.contains(lal_addr[i]);
403  m->second->addLockedAddr(LockedAddr(lal_addr[i], lal_cid[i]));
404  }
405 
406  // unserialize the backing stores
407  unsigned int nbr_of_stores;
408  UNSERIALIZE_SCALAR(nbr_of_stores);
409 
410  for (unsigned int i = 0; i < nbr_of_stores; ++i) {
411  ScopedCheckpointSection sec(cp, csprintf("store%d", i));
412  unserializeStore(cp);
413  }
414 
415 }
416 
417 void
419 {
420  const uint32_t chunk_size = 16384;
421 
422  unsigned int store_id;
423  UNSERIALIZE_SCALAR(store_id);
424 
425  std::string filename;
426  UNSERIALIZE_SCALAR(filename);
427  std::string filepath = cp.getCptDir() + "/" + filename;
428 
429  // mmap memoryfile
430  gzFile compressed_mem = gzopen(filepath.c_str(), "rb");
431  if (compressed_mem == NULL)
432  fatal("Can't open physical memory checkpoint file '%s'", filename);
433 
434  // we've already got the actual backing store mapped
435  uint8_t* pmem = backingStore[store_id].pmem;
436  AddrRange range = backingStore[store_id].range;
437 
438  long range_size;
439  UNSERIALIZE_SCALAR(range_size);
440 
441  DPRINTF(Checkpoint, "Unserializing physical memory %s with size %d\n",
442  filename, range_size);
443 
444  if (range_size != range.size())
445  fatal("Memory range size has changed! Saw %lld, expected %lld\n",
446  range_size, range.size());
447 
448  uint64_t curr_size = 0;
449  long* temp_page = new long[chunk_size];
450  long* pmem_current;
451  uint32_t bytes_read;
452  while (curr_size < range.size()) {
453  bytes_read = gzread(compressed_mem, temp_page, chunk_size);
454  if (bytes_read == 0)
455  break;
456 
457  assert(bytes_read % sizeof(long) == 0);
458 
459  for (uint32_t x = 0; x < bytes_read / sizeof(long); x++) {
460  // Only copy bytes that are non-zero, so we don't give
461  // the VM system hell
462  if (*(temp_page + x) != 0) {
463  pmem_current = (long*)(pmem + curr_size + x * sizeof(long));
464  *pmem_current = *(temp_page + x);
465  }
466  }
467  curr_size += bytes_read;
468  }
469 
470  delete[] temp_page;
471 
472  if (gzclose(compressed_mem))
473  fatal("Close failed on physical memory checkpoint file '%s'\n",
474  filename);
475 }
476 
477 } // namespace memory
478 } // namespace gem5
fatal
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:189
gem5::AddrRange::to_string
std::string to_string() const
Get a string representation of the range.
Definition: addr_range.hh:333
gem5::Packet::isRequest
bool isRequest() const
Definition: packet.hh:586
warn
#define warn(...)
Definition: logging.hh:245
gem5::memory::PhysicalMemory::serialize
void serialize(CheckpointOut &cp) const override
Serialize all the memories in the system.
Definition: physical.cc:316
gem5::CheckpointIn::dir
static std::string dir()
Get the current checkout directory name.
Definition: serialize.cc:154
serialize.hh
UNSERIALIZE_SCALAR
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:575
memory
Definition: mem.h:38
abstract_mem.hh
UNSERIALIZE_CONTAINER
#define UNSERIALIZE_CONTAINER(member)
Definition: serialize.hh:634
gem5::memory::PhysicalMemory::access
void access(PacketPtr pkt)
Perform an untimed memory access and update all the state (e.g.
Definition: physical.cc:298
gem5::CheckpointIn
Definition: serialize.hh:68
gem5::ArmISA::f
Bitfield< 6 > f
Definition: misc_types.hh:67
gem5::memory::PhysicalMemory::unserialize
void unserialize(CheckpointIn &cp) override
Unserialize the memories in the system.
Definition: physical.cc:393
gem5::memory::PhysicalMemory::backingStore
std::vector< BackingStoreEntry > backingStore
Definition: physical.hh:146
gem5::memory::PhysicalMemory::unserializeStore
void unserializeStore(CheckpointIn &cp)
Unserialize a specific backing store, identified by a section.
Definition: physical.cc:418
sc_dt::to_string
const std::string to_string(sc_enc enc)
Definition: sc_fxdefs.cc:91
gem5::memory::PhysicalMemory::serializeStore
void serializeStore(CheckpointOut &cp, unsigned int store_id, AddrRange range, uint8_t *pmem) const
Serialize a specific store.
Definition: physical.cc:346
std::vector
STL vector class.
Definition: stl.hh:37
gem5::csprintf
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:161
gem5::ArmISA::i
Bitfield< 7 > i
Definition: misc_types.hh:66
gem5::memory::PhysicalMemory::PhysicalMemory
PhysicalMemory(const PhysicalMemory &)
gem5::memory::PhysicalMemory::addrMap
AddrRangeMap< AbstractMemory *, 1 > addrMap
Definition: physical.hh:131
gem5::AddrRange::interleaved
bool interleaved() const
Determine if the range is interleaved or not.
Definition: addr_range.hh:260
DPRINTF
#define DPRINTF(x,...)
Definition: trace.hh:186
gem5::Packet
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:283
gem5::memory::PhysicalMemory::~PhysicalMemory
~PhysicalMemory()
Unmap all the backing store we have used.
Definition: physical.cc:248
gem5::memory::PhysicalMemory::mmapUsingNoReserve
const bool mmapUsingNoReserve
Definition: physical.hh:140
gem5::memory::AbstractMemory
An abstract memory represents a contiguous block of physical memory, with an associated address range...
Definition: abstract_mem.hh:110
gem5::memory::PhysicalMemory::sharedBackstore
const std::string sharedBackstore
Definition: physical.hh:142
gem5::ArmISA::s
Bitfield< 4 > s
Definition: misc_types.hh:561
gem5::memory::PhysicalMemory::memories
std::vector< AbstractMemory * > memories
Definition: physical.hh:134
gem5::MipsISA::l
Bitfield< 5 > l
Definition: pra_constants.hh:323
gem5::AddrRange::size
Addr size() const
Get the size of the address range.
Definition: addr_range.hh:300
gem5::RiscvISA::locked_addrs
std::unordered_map< int, std::stack< Addr > > locked_addrs
Definition: locked_mem.cc:12
gem5::ArmISA::c
Bitfield< 29 > c
Definition: misc_types.hh:53
gem5::Addr
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
gem5::memory::PhysicalMemory::functionalAccess
void functionalAccess(PacketPtr pkt)
Perform an untimed memory read or write without changing anything but the memory itself.
Definition: physical.cc:307
SERIALIZE_SCALAR
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:568
gem5::memory::PhysicalMemory::name
const std::string name() const
Return the name for debugging and for creation of sections for checkpointing.
Definition: physical.hh:187
gem5::CheckpointIn::getCptDir
const std::string getCptDir()
Definition: serialize.hh:85
panic_if
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition: logging.hh:203
gem5::ArmISA::m
Bitfield< 0 > m
Definition: misc_types.hh:394
gem5::RiscvISA::x
Bitfield< 3 > x
Definition: pagetable.hh:73
SERIALIZE_CONTAINER
#define SERIALIZE_CONTAINER(member)
Definition: serialize.hh:626
gem5::memory::PhysicalMemory::size
uint64_t size
Definition: physical.hh:137
physical.hh
gem5::memory::LockedAddr
Locked address class that represents a physical address and a context id.
Definition: abstract_mem.hh:67
gem5::memory::PhysicalMemory::isMemAddr
bool isMemAddr(Addr addr) const
Check if a physical address is within a range of a memory that is part of the global address map.
Definition: physical.cc:256
gem5::MipsISA::r
r
Definition: pra_constants.hh:98
gem5::CheckpointOut
std::ostream CheckpointOut
Definition: serialize.hh:66
trace.hh
gem5::AddrRange
The AddrRange class encapsulates an address range, and supports a number of tests to check if two ran...
Definition: addr_range.hh:71
std::list< AddrRange >
fatal_if
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition: logging.hh:225
gem5
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Definition: decoder.cc:40
gem5::Packet::getAddrRange
AddrRange getAddrRange() const
Get address range to which this packet belongs.
Definition: packet.cc:225
gem5::memory::PhysicalMemory::getConfAddrRanges
AddrRangeList getConfAddrRanges() const
Get the memory ranges for all memories that are to be reported to the configuration table.
Definition: physical.cc:262
gem5::Serializable::ScopedCheckpointSection
Definition: serialize.hh:172
gem5::memory::PhysicalMemory::createBackingStore
void createBackingStore(AddrRange range, const std::vector< AbstractMemory * > &_memories, bool conf_table_reported, bool in_addr_map, bool kvm_map)
Create the memory region providing the backing store for a given address range that corresponds to a ...
Definition: physical.cc:190
panic
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:177
gem5::X86ISA::addr
Bitfield< 3 > addr
Definition: types.hh:84

Generated on Tue Sep 21 2021 12:25:34 for gem5 by doxygen 1.8.17