gem5  v21.0.0.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
disk_image.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2001-2005 The Regents of The University of Michigan
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met: redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer;
9  * redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution;
12  * neither the name of the copyright holders nor the names of its
13  * contributors may be used to endorse or promote products derived from
14  * this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
34 
35 #include <sys/types.h>
36 #include <sys/uio.h>
37 #include <unistd.h>
38 
39 #include <cerrno>
40 #include <cstring>
41 #include <fstream>
42 #include <string>
43 
44 #include "base/callback.hh"
45 #include "base/logging.hh"
46 #include "base/trace.hh"
47 #include "debug/DiskImageRead.hh"
48 #include "debug/DiskImageWrite.hh"
49 #include "sim/byteswap.hh"
50 #include "sim/serialize.hh"
51 #include "sim/sim_exit.hh"
52 
54 //
55 // Raw Disk image
56 //
58  : DiskImage(p), disk_size(0)
59 {
60  open(p.image_file, p.read_only);
61 }
62 
64 {
65  close();
66 }
67 
68 void
70 {
71  if (initialized && !readonly)
72  panic("Attempting to fork system with read-write raw disk image.");
73 
74  const Params &p = dynamic_cast<const Params &>(params());
75  close();
76  open(p.image_file, p.read_only);
77 }
78 
79 void
80 RawDiskImage::open(const std::string &filename, bool rd_only)
81 {
82  if (!filename.empty()) {
83  initialized = true;
84  readonly = rd_only;
85  file = filename;
86 
87  std::ios::openmode mode = std::ios::in | std::ios::binary;
88  if (!readonly)
89  mode |= std::ios::out;
90  stream.open(file.c_str(), mode);
91  if (!stream.is_open())
92  panic("Error opening %s", filename);
93  }
94 }
95 
96 void
98 {
99  stream.close();
100 }
101 
102 std::streampos
104 {
105  if (disk_size == 0) {
106  if (!stream.is_open())
107  panic("file not open!\n");
108  stream.seekg(0, std::ios::end);
109  disk_size = stream.tellg();
110  }
111 
112  return disk_size / SectorSize;
113 }
114 
115 std::streampos
116 RawDiskImage::read(uint8_t *data, std::streampos offset) const
117 {
118  if (!initialized)
119  panic("RawDiskImage not initialized");
120 
121  if (!stream.is_open())
122  panic("file not open!\n");
123 
124  stream.seekg(offset * SectorSize, std::ios::beg);
125  if (!stream.good())
126  panic("Could not seek to location in file");
127 
128  std::streampos pos = stream.tellg();
129  stream.read((char *)data, SectorSize);
130 
131  DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset);
132  DDUMP(DiskImageRead, data, SectorSize);
133 
134  return stream.tellg() - pos;
135 }
136 
137 std::streampos
138 RawDiskImage::write(const uint8_t *data, std::streampos offset)
139 {
140  if (!initialized)
141  panic("RawDiskImage not initialized");
142 
143  if (readonly)
144  panic("Cannot write to a read only disk image");
145 
146  if (!stream.is_open())
147  panic("file not open!\n");
148 
149  stream.seekp(offset * SectorSize, std::ios::beg);
150  if (!stream.good())
151  panic("Could not seek to location in file");
152 
153  DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset);
154  DDUMP(DiskImageWrite, data, SectorSize);
155 
156  std::streampos pos = stream.tellp();
157  stream.write((const char *)data, SectorSize);
158  return stream.tellp() - pos;
159 }
160 
162 //
163 // Copy on Write Disk image
164 //
165 const uint32_t CowDiskImage::VersionMajor = 1;
166 const uint32_t CowDiskImage::VersionMinor = 0;
167 
169  : DiskImage(p), filename(p.image_file), child(p.child), table(NULL)
170 {
171  if (filename.empty()) {
172  initSectorTable(p.table_size);
173  } else {
174  if (!open(filename)) {
175  if (p.read_only)
176  fatal("could not open read-only file");
177  initSectorTable(p.table_size);
178  }
179 
180  if (!p.read_only)
181  registerExitCallback([this]() { save(); });
182  }
183 }
184 
186 {
187  SectorTable::iterator i = table->begin();
188  SectorTable::iterator end = table->end();
189 
190  while (i != end) {
191  delete (*i).second;
192  ++i;
193  }
194 }
195 
196 void
198 {
199  if (!dynamic_cast<const Params &>(params()).read_only &&
200  !filename.empty()) {
201  inform("Disabling saving of COW image in forked child process.\n");
202  filename = "";
203  }
204 }
205 
206 void
207 SafeRead(std::ifstream &stream, void *data, int count)
208 {
209  stream.read((char *)data, count);
210  if (!stream.is_open())
211  panic("file not open");
212 
213  if (stream.eof())
214  panic("premature end-of-file");
215 
216  if (stream.bad() || stream.fail())
217  panic("error reading cowdisk image");
218 }
219 
220 template<class T>
221 void
222 SafeRead(std::ifstream &stream, T &data)
223 {
224  SafeRead(stream, &data, sizeof(data));
225 }
226 
227 template<class T>
228 void
229 SafeReadSwap(std::ifstream &stream, T &data)
230 {
231  SafeRead(stream, &data, sizeof(data));
232  data = letoh(data); //is this the proper byte order conversion?
233 }
234 
235 bool
236 CowDiskImage::open(const std::string &file)
237 {
238  std::ifstream stream(file.c_str());
239  if (!stream.is_open())
240  return false;
241 
242  if (stream.fail() || stream.bad())
243  panic("Error opening %s", file);
244 
245  uint64_t magic;
246  SafeRead(stream, magic);
247 
248  if (memcmp(&magic, "COWDISK!", sizeof(magic)) != 0)
249  panic("Could not open %s: Invalid magic", file);
250 
251  uint32_t major, minor;
252  SafeReadSwap(stream, major);
253  SafeReadSwap(stream, minor);
254 
255  if (major != VersionMajor && minor != VersionMinor)
256  panic("Could not open %s: invalid version %d.%d != %d.%d",
257  file, major, minor, VersionMajor, VersionMinor);
258 
259  uint64_t sector_count;
260  SafeReadSwap(stream, sector_count);
261  table = new SectorTable(sector_count);
262 
263 
264  for (uint64_t i = 0; i < sector_count; i++) {
265  uint64_t offset;
266  SafeReadSwap(stream, offset);
267 
268  Sector *sector = new Sector;
269  SafeRead(stream, sector, sizeof(Sector));
270 
271  assert(table->find(offset) == table->end());
272  (*table)[offset] = sector;
273  }
274 
275  stream.close();
276 
277  initialized = true;
278  return true;
279 }
280 
281 void
283 {
284  table = new SectorTable(hash_size);
285 
286  initialized = true;
287 }
288 
289 void
290 SafeWrite(std::ofstream &stream, const void *data, int count)
291 {
292  stream.write((const char *)data, count);
293  if (!stream.is_open())
294  panic("file not open");
295 
296  if (stream.eof())
297  panic("premature end-of-file");
298 
299  if (stream.bad() || stream.fail())
300  panic("error reading cowdisk image");
301 }
302 
303 template<class T>
304 void
305 SafeWrite(std::ofstream &stream, const T &data)
306 {
307  SafeWrite(stream, &data, sizeof(data));
308 }
309 
310 template<class T>
311 void
312 SafeWriteSwap(std::ofstream &stream, const T &data)
313 {
314  T swappeddata = letoh(data); //is this the proper byte order conversion?
315  SafeWrite(stream, &swappeddata, sizeof(data));
316 }
317 void
319 {
320  // filename will be set to the empty string to disable saving of
321  // the COW image in a forked child process. Save will still be
322  // called because there is no easy way to unregister the exit
323  // callback.
324  if (!filename.empty())
325  save(filename);}
326 
327 void
328 CowDiskImage::save(const std::string &file) const
329 {
330  if (!initialized)
331  panic("RawDiskImage not initialized");
332 
333  std::ofstream stream(file.c_str());
334  if (!stream.is_open() || stream.fail() || stream.bad())
335  panic("Error opening %s", file);
336 
337  uint64_t magic;
338  memcpy(&magic, "COWDISK!", sizeof(magic));
339  SafeWrite(stream, magic);
340 
341  SafeWriteSwap(stream, (uint32_t)VersionMajor);
342  SafeWriteSwap(stream, (uint32_t)VersionMinor);
343  SafeWriteSwap(stream, (uint64_t)table->size());
344 
345  uint64_t size = table->size();
346  SectorTable::iterator iter = table->begin();
347  SectorTable::iterator end = table->end();
348 
349  for (uint64_t i = 0; i < size; i++) {
350  if (iter == end)
351  panic("Incorrect Table Size during save of COW disk image");
352 
353  SafeWriteSwap(stream, (uint64_t)(*iter).first);
354  SafeWrite(stream, (*iter).second->data, sizeof(Sector));
355  ++iter;
356  }
357 
358  stream.close();
359 }
360 
361 void
363 {
364  SectorTable::iterator i = table->begin();
365  SectorTable::iterator end = table->end();
366 
367  while (i != end) {
368  child->write((*i).second->data, (*i).first);
369  ++i;
370  }
371 }
372 
373 std::streampos
375 { return child->size(); }
376 
377 std::streampos
378 CowDiskImage::read(uint8_t *data, std::streampos offset) const
379 {
380  if (!initialized)
381  panic("CowDiskImage not initialized");
382 
383  if (offset > size())
384  panic("access out of bounds");
385 
386  SectorTable::const_iterator i = table->find(offset);
387  if (i == table->end())
388  return child->read(data, offset);
389  else {
390  memcpy(data, (*i).second->data, SectorSize);
391  DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset);
392  DDUMP(DiskImageRead, data, SectorSize);
393  return SectorSize;
394  }
395 }
396 
397 std::streampos
398 CowDiskImage::write(const uint8_t *data, std::streampos offset)
399 {
400  if (!initialized)
401  panic("RawDiskImage not initialized");
402 
403  if (offset > size())
404  panic("access out of bounds");
405 
406  SectorTable::iterator i = table->find(offset);
407  if (i == table->end()) {
408  Sector *sector = new Sector;
409  memcpy(sector, data, SectorSize);
410  table->insert(make_pair(offset, sector));
411  } else {
412  memcpy((*i).second->data, data, SectorSize);
413  }
414 
415  DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset);
416  DDUMP(DiskImageWrite, data, SectorSize);
417 
418  return SectorSize;
419 }
420 
421 void
423 {
424  std::string cowFilename = name() + ".cow";
425  SERIALIZE_SCALAR(cowFilename);
426  save(CheckpointIn::dir() + "/" + cowFilename);
427 }
428 
429 void
431 {
432  std::string cowFilename;
433  UNSERIALIZE_SCALAR(cowFilename);
434  cowFilename = cp.getCptDir() + "/" + cowFilename;
435  open(cowFilename);
436 }
fatal
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:183
DiskImage::write
virtual std::streampos write(const uint8_t *data, std::streampos offset)=0
CowDiskImage::write
std::streampos write(const uint8_t *data, std::streampos offset) override
Definition: disk_image.cc:398
CowDiskImage::Sector
Definition: disk_image.hh:111
data
const char data[]
Definition: circlebuf.test.cc:47
serialize.hh
UNSERIALIZE_SCALAR
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:591
DiskImage::initialized
bool initialized
Definition: disk_image.hh:52
ArmISA::i
Bitfield< 7 > i
Definition: miscregs_types.hh:63
SectorSize
#define SectorSize
Definition: disk_image.hh:44
RawDiskImage::readonly
bool readonly
Definition: disk_image.hh:75
disk_image.hh
SafeRead
void SafeRead(std::ifstream &stream, void *data, int count)
Definition: disk_image.cc:207
CowDiskImage::notifyFork
void notifyFork() override
Notify a child process of a fork.
Definition: disk_image.cc:197
RawDiskImage::size
std::streampos size() const override
Definition: disk_image.cc:103
X86ISA::count
count
Definition: misc.hh:703
sim_exit.hh
DiskImage::size
virtual std::streampos size() const =0
RawDiskImage::file
std::string file
Definition: disk_image.hh:74
letoh
T letoh(T value)
Definition: byteswap.hh:142
cp
Definition: cprintf.cc:37
CowDiskImage::table
SectorTable * table
Definition: disk_image.hh:119
registerExitCallback
void registerExitCallback(const std::function< void()> &callback)
Register an exit callback.
Definition: core.cc:137
DiskImage
Basic interface for accessing a disk image.
Definition: disk_image.hh:49
CowDiskImage::size
std::streampos size() const override
Definition: disk_image.cc:374
CowDiskImage::child
DiskImage * child
Definition: disk_image.hh:118
DPRINTF
#define DPRINTF(x,...)
Definition: trace.hh:237
CowDiskImage::read
std::streampos read(uint8_t *data, std::streampos offset) const override
Definition: disk_image.cc:378
CowDiskImage::unserialize
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: disk_image.cc:430
CowDiskImage::writeback
void writeback()
Definition: disk_image.cc:362
ArmISA::mode
Bitfield< 4, 0 > mode
Definition: miscregs_types.hh:70
SafeWriteSwap
void SafeWriteSwap(std::ofstream &stream, const T &data)
Definition: disk_image.cc:312
RawDiskImage::~RawDiskImage
~RawDiskImage()
Definition: disk_image.cc:63
CowDiskImage::~CowDiskImage
~CowDiskImage()
Definition: disk_image.cc:185
RawDiskImage::stream
std::fstream stream
Definition: disk_image.hh:73
SafeReadSwap
void SafeReadSwap(std::ifstream &stream, T &data)
Definition: disk_image.cc:229
RawDiskImage::RawDiskImage
RawDiskImage(const Params &p)
Definition: disk_image.cc:57
RawDiskImage::notifyFork
void notifyFork() override
Notify a child process of a fork.
Definition: disk_image.cc:69
RawDiskImage::close
void close()
Definition: disk_image.cc:97
CowDiskImage::open
bool open(const std::string &file)
Definition: disk_image.cc:236
RawDiskImage::write
std::streampos write(const uint8_t *data, std::streampos offset) override
Definition: disk_image.cc:138
SERIALIZE_SCALAR
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:584
DDUMP
#define DDUMP(x, data, count)
DPRINTF is a debugging trace facility that allows one to selectively enable tracing statements.
Definition: trace.hh:236
SimObject::name
virtual const std::string name() const
Definition: sim_object.hh:182
inform
#define inform(...)
Definition: logging.hh:240
CowDiskImage::VersionMajor
static const uint32_t VersionMajor
Definition: disk_image.hh:107
CowDiskImage::VersionMinor
static const uint32_t VersionMinor
Definition: disk_image.hh:108
SafeWrite
void SafeWrite(std::ofstream &stream, const void *data, int count)
Definition: disk_image.cc:290
logging.hh
DiskImage::read
virtual std::streampos read(uint8_t *data, std::streampos offset) const =0
CheckpointOut
std::ostream CheckpointOut
Definition: serialize.hh:64
trace.hh
RawDiskImage::open
void open(const std::string &filename, bool rd_only=false)
Definition: disk_image.cc:80
CowDiskImage::filename
std::string filename
Definition: disk_image.hh:117
RawDiskImage::disk_size
std::streampos disk_size
Definition: disk_image.hh:76
CheckpointIn::dir
static std::string dir()
Get the current checkout directory name.
Definition: serialize.cc:262
SimObject::params
const Params & params() const
Definition: sim_object.hh:168
MipsISA::p
Bitfield< 0 > p
Definition: pra_constants.hh:323
CowDiskImage::CowDiskImage
CowDiskImage(const Params &p)
Definition: disk_image.cc:168
CheckpointIn
Definition: serialize.hh:68
CowDiskImage::save
void save() const
Definition: disk_image.cc:318
image_file
const uint8_t image_file[]
This image file contains the text "This is a test image.\n" 31 times.
Definition: small_image_file.test.hh:37
CowDiskImage::SectorTable
std::unordered_map< uint64_t, Sector * > SectorTable
Definition: disk_image.hh:114
callback.hh
DiskImage::Params
DiskImageParams Params
Definition: disk_image.hh:55
byteswap.hh
CowDiskImage::serialize
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: disk_image.cc:422
RawDiskImage::read
std::streampos read(uint8_t *data, std::streampos offset) const override
Definition: disk_image.cc:116
panic
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:171
CowDiskImage::initSectorTable
void initSectorTable(int hash_size)
Definition: disk_image.cc:282
ArmISA::offset
Bitfield< 23, 0 > offset
Definition: types.hh:153

Generated on Tue Mar 23 2021 19:41:26 for gem5 by doxygen 1.8.17