2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
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.
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.
30 * Disk Image Definitions
33 #include "dev/storage/disk_image.hh"
35 #include <sys/types.h>
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/sim_exit.hh"
54 ////////////////////////////////////////////////////////////////////////
58 RawDiskImage::RawDiskImage(const Params
&p
)
59 : DiskImage(p
), disk_size(0)
61 open(p
.image_file
, p
.read_only
);
64 RawDiskImage::~RawDiskImage()
70 RawDiskImage::notifyFork()
72 if (initialized
&& !readonly
)
73 panic("Attempting to fork system with read-write raw disk image.");
75 const Params
&p
= dynamic_cast<const Params
&>(params());
77 open(p
.image_file
, p
.read_only
);
81 RawDiskImage::open(const string
&filename
, bool rd_only
)
83 if (!filename
.empty()) {
88 ios::openmode mode
= ios::in
| ios::binary
;
91 stream
.open(file
.c_str(), mode
);
92 if (!stream
.is_open())
93 panic("Error opening %s", filename
);
104 RawDiskImage::size() const
106 if (disk_size
== 0) {
107 if (!stream
.is_open())
108 panic("file not open!\n");
109 stream
.seekg(0, ios::end
);
110 disk_size
= stream
.tellg();
113 return disk_size
/ SectorSize
;
117 RawDiskImage::read(uint8_t *data
, std::streampos offset
) const
120 panic("RawDiskImage not initialized");
122 if (!stream
.is_open())
123 panic("file not open!\n");
125 stream
.seekg(offset
* SectorSize
, ios::beg
);
127 panic("Could not seek to location in file");
129 streampos pos
= stream
.tellg();
130 stream
.read((char *)data
, SectorSize
);
132 DPRINTF(DiskImageRead
, "read: offset=%d\n", (uint64_t)offset
);
133 DDUMP(DiskImageRead
, data
, SectorSize
);
135 return stream
.tellg() - pos
;
139 RawDiskImage::write(const uint8_t *data
, std::streampos offset
)
142 panic("RawDiskImage not initialized");
145 panic("Cannot write to a read only disk image");
147 if (!stream
.is_open())
148 panic("file not open!\n");
150 stream
.seekp(offset
* SectorSize
, ios::beg
);
152 panic("Could not seek to location in file");
154 DPRINTF(DiskImageWrite
, "write: offset=%d\n", (uint64_t)offset
);
155 DDUMP(DiskImageWrite
, data
, SectorSize
);
157 streampos pos
= stream
.tellp();
158 stream
.write((const char *)data
, SectorSize
);
159 return stream
.tellp() - pos
;
162 ////////////////////////////////////////////////////////////////////////
164 // Copy on Write Disk image
166 const uint32_t CowDiskImage::VersionMajor
= 1;
167 const uint32_t CowDiskImage::VersionMinor
= 0;
169 CowDiskImage::CowDiskImage(const Params
&p
)
170 : DiskImage(p
), filename(p
.image_file
), child(p
.child
), table(NULL
)
172 if (filename
.empty()) {
173 initSectorTable(p
.table_size
);
175 if (!open(filename
)) {
177 fatal("could not open read-only file");
178 initSectorTable(p
.table_size
);
182 registerExitCallback([this]() { save(); });
186 CowDiskImage::~CowDiskImage()
188 SectorTable::iterator i
= table
->begin();
189 SectorTable::iterator end
= table
->end();
198 CowDiskImage::notifyFork()
200 if (!dynamic_cast<const Params
&>(params()).read_only
&&
202 inform("Disabling saving of COW image in forked child process.\n");
208 SafeRead(ifstream
&stream
, void *data
, int count
)
210 stream
.read((char *)data
, count
);
211 if (!stream
.is_open())
212 panic("file not open");
215 panic("premature end-of-file");
217 if (stream
.bad() || stream
.fail())
218 panic("error reading cowdisk image");
223 SafeRead(ifstream
&stream
, T
&data
)
225 SafeRead(stream
, &data
, sizeof(data
));
230 SafeReadSwap(ifstream
&stream
, T
&data
)
232 SafeRead(stream
, &data
, sizeof(data
));
233 data
= letoh(data
); //is this the proper byte order conversion?
237 CowDiskImage::open(const string
&file
)
239 ifstream
stream(file
.c_str());
240 if (!stream
.is_open())
243 if (stream
.fail() || stream
.bad())
244 panic("Error opening %s", file
);
247 SafeRead(stream
, magic
);
249 if (memcmp(&magic
, "COWDISK!", sizeof(magic
)) != 0)
250 panic("Could not open %s: Invalid magic", file
);
252 uint32_t major
, minor
;
253 SafeReadSwap(stream
, major
);
254 SafeReadSwap(stream
, minor
);
256 if (major
!= VersionMajor
&& minor
!= VersionMinor
)
257 panic("Could not open %s: invalid version %d.%d != %d.%d",
258 file
, major
, minor
, VersionMajor
, VersionMinor
);
260 uint64_t sector_count
;
261 SafeReadSwap(stream
, sector_count
);
262 table
= new SectorTable(sector_count
);
265 for (uint64_t i
= 0; i
< sector_count
; i
++) {
267 SafeReadSwap(stream
, offset
);
269 Sector
*sector
= new Sector
;
270 SafeRead(stream
, sector
, sizeof(Sector
));
272 assert(table
->find(offset
) == table
->end());
273 (*table
)[offset
] = sector
;
283 CowDiskImage::initSectorTable(int hash_size
)
285 table
= new SectorTable(hash_size
);
291 SafeWrite(ofstream
&stream
, const void *data
, int count
)
293 stream
.write((const char *)data
, count
);
294 if (!stream
.is_open())
295 panic("file not open");
298 panic("premature end-of-file");
300 if (stream
.bad() || stream
.fail())
301 panic("error reading cowdisk image");
306 SafeWrite(ofstream
&stream
, const T
&data
)
308 SafeWrite(stream
, &data
, sizeof(data
));
313 SafeWriteSwap(ofstream
&stream
, const T
&data
)
315 T swappeddata
= letoh(data
); //is this the proper byte order conversion?
316 SafeWrite(stream
, &swappeddata
, sizeof(data
));
319 CowDiskImage::save() const
321 // filename will be set to the empty string to disable saving of
322 // the COW image in a forked child process. Save will still be
323 // called because there is no easy way to unregister the exit
325 if (!filename
.empty())
329 CowDiskImage::save(const string
&file
) const
332 panic("RawDiskImage not initialized");
334 ofstream
stream(file
.c_str());
335 if (!stream
.is_open() || stream
.fail() || stream
.bad())
336 panic("Error opening %s", file
);
339 memcpy(&magic
, "COWDISK!", sizeof(magic
));
340 SafeWrite(stream
, magic
);
342 SafeWriteSwap(stream
, (uint32_t)VersionMajor
);
343 SafeWriteSwap(stream
, (uint32_t)VersionMinor
);
344 SafeWriteSwap(stream
, (uint64_t)table
->size());
346 uint64_t size
= table
->size();
347 SectorTable::iterator iter
= table
->begin();
348 SectorTable::iterator end
= table
->end();
350 for (uint64_t i
= 0; i
< size
; i
++) {
352 panic("Incorrect Table Size during save of COW disk image");
354 SafeWriteSwap(stream
, (uint64_t)(*iter
).first
);
355 SafeWrite(stream
, (*iter
).second
->data
, sizeof(Sector
));
363 CowDiskImage::writeback()
365 SectorTable::iterator i
= table
->begin();
366 SectorTable::iterator end
= table
->end();
369 child
->write((*i
).second
->data
, (*i
).first
);
375 CowDiskImage::size() const
376 { return child
->size(); }
379 CowDiskImage::read(uint8_t *data
, std::streampos offset
) const
382 panic("CowDiskImage not initialized");
385 panic("access out of bounds");
387 SectorTable::const_iterator i
= table
->find(offset
);
388 if (i
== table
->end())
389 return child
->read(data
, offset
);
391 memcpy(data
, (*i
).second
->data
, SectorSize
);
392 DPRINTF(DiskImageRead
, "read: offset=%d\n", (uint64_t)offset
);
393 DDUMP(DiskImageRead
, data
, SectorSize
);
399 CowDiskImage::write(const uint8_t *data
, std::streampos offset
)
402 panic("RawDiskImage not initialized");
405 panic("access out of bounds");
407 SectorTable::iterator i
= table
->find(offset
);
408 if (i
== table
->end()) {
409 Sector
*sector
= new Sector
;
410 memcpy(sector
, data
, SectorSize
);
411 table
->insert(make_pair(offset
, sector
));
413 memcpy((*i
).second
->data
, data
, SectorSize
);
416 DPRINTF(DiskImageWrite
, "write: offset=%d\n", (uint64_t)offset
);
417 DDUMP(DiskImageWrite
, data
, SectorSize
);
423 CowDiskImage::serialize(CheckpointOut
&cp
) const
425 string cowFilename
= name() + ".cow";
426 SERIALIZE_SCALAR(cowFilename
);
427 save(CheckpointIn::dir() + "/" + cowFilename
);
431 CowDiskImage::unserialize(CheckpointIn
&cp
)
434 UNSERIALIZE_SCALAR(cowFilename
);
435 cowFilename
= cp
.getCptDir() + "/" + cowFilename
;