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.
28 * Authors: Nathan Binkert
32 * Disk Image Definitions
35 #include <sys/types.h>
44 #include "base/callback.hh"
45 #include "base/misc.hh"
46 #include "base/trace.hh"
47 #include "dev/disk_image.hh"
48 #include "params/CowDiskImage.hh"
49 #include "params/RawDiskImage.hh"
50 #include "sim/sim_exit.hh"
51 #include "sim/byteswap.hh"
55 ////////////////////////////////////////////////////////////////////////
59 RawDiskImage::RawDiskImage(const string
&name
, const string
&filename
,
61 : DiskImage(name
), disk_size(0)
62 { open(filename
, rd_only
); }
64 RawDiskImage::~RawDiskImage()
68 RawDiskImage::open(const string
&filename
, bool rd_only
)
70 if (!filename
.empty()) {
75 ios::openmode mode
= ios::in
| ios::binary
;
78 stream
.open(file
.c_str(), mode
);
79 if (!stream
.is_open())
80 panic("Error opening %s", filename
);
91 RawDiskImage::size() const
94 if (!stream
.is_open())
95 panic("file not open!\n");
96 stream
.seekg(0, ios::end
);
97 disk_size
= stream
.tellg();
100 return disk_size
/ SectorSize
;
104 RawDiskImage::read(uint8_t *data
, off_t offset
) const
107 panic("RawDiskImage not initialized");
109 if (!stream
.is_open())
110 panic("file not open!\n");
112 if (stream
.seekg(offset
* SectorSize
, ios::beg
) < 0)
113 panic("Could not seek to location in file");
115 streampos pos
= stream
.tellg();
116 stream
.read((char *)data
, SectorSize
);
118 DPRINTF(DiskImageRead
, "read: offset=%d\n", (uint64_t)offset
);
119 DDUMP(DiskImageRead
, data
, SectorSize
);
121 return stream
.tellg() - pos
;
125 RawDiskImage::write(const uint8_t *data
, off_t offset
)
128 panic("RawDiskImage not initialized");
131 panic("Cannot write to a read only disk image");
133 if (!stream
.is_open())
134 panic("file not open!\n");
136 if (stream
.seekp(offset
* SectorSize
, ios::beg
) < 0)
137 panic("Could not seek to location in file");
139 DPRINTF(DiskImageWrite
, "write: offset=%d\n", (uint64_t)offset
);
140 DDUMP(DiskImageWrite
, data
, SectorSize
);
142 streampos pos
= stream
.tellp();
143 stream
.write((const char *)data
, SectorSize
);
144 return stream
.tellp() - pos
;
148 RawDiskImageParams::create()
150 return new RawDiskImage(name
, image_file
, read_only
);
153 ////////////////////////////////////////////////////////////////////////
155 // Copy on Write Disk image
157 const int CowDiskImage::VersionMajor
= 1;
158 const int CowDiskImage::VersionMinor
= 0;
160 CowDiskImage::CowDiskImage(const string
&name
, DiskImage
*kid
, int hash_size
)
161 : DiskImage(name
), child(kid
), table(NULL
)
164 class CowDiskCallback
: public Callback
170 CowDiskCallback(CowDiskImage
*i
) : image(i
) {}
171 void process() { image
->save(); delete this; }
174 CowDiskImage::CowDiskImage(const string
&name
, DiskImage
*kid
, int hash_size
,
175 const string
&file
, bool read_only
)
176 : DiskImage(name
), filename(file
), child(kid
), table(NULL
)
178 if (!open(filename
)) {
179 assert(!read_only
&& "why have a non-existent read only file?");
184 registerExitCallback(new CowDiskCallback(this));
187 CowDiskImage::~CowDiskImage()
189 SectorTable::iterator i
= table
->begin();
190 SectorTable::iterator end
= table
->end();
199 SafeRead(ifstream
&stream
, void *data
, int count
)
201 stream
.read((char *)data
, count
);
202 if (!stream
.is_open())
203 panic("file not open");
206 panic("premature end-of-file");
208 if (stream
.bad() || stream
.fail())
209 panic("error reading cowdisk image");
214 SafeRead(ifstream
&stream
, T
&data
)
216 SafeRead(stream
, &data
, sizeof(data
));
221 SafeReadSwap(ifstream
&stream
, T
&data
)
223 SafeRead(stream
, &data
, sizeof(data
));
224 data
= letoh(data
); //is this the proper byte order conversion?
228 CowDiskImage::open(const string
&file
)
230 ifstream
stream(file
.c_str());
231 if (!stream
.is_open())
234 if (stream
.fail() || stream
.bad())
235 panic("Error opening %s", file
);
238 SafeRead(stream
, magic
);
240 if (memcmp(&magic
, "COWDISK!", sizeof(magic
)) != 0)
241 panic("Could not open %s: Invalid magic", file
);
243 uint32_t major
, minor
;
244 SafeReadSwap(stream
, major
);
245 SafeReadSwap(stream
, minor
);
247 if (major
!= VersionMajor
&& minor
!= VersionMinor
)
248 panic("Could not open %s: invalid version %d.%d != %d.%d",
249 file
, major
, minor
, VersionMajor
, VersionMinor
);
251 uint64_t sector_count
;
252 SafeReadSwap(stream
, sector_count
);
253 table
= new SectorTable(sector_count
);
256 for (uint64_t i
= 0; i
< sector_count
; i
++) {
258 SafeReadSwap(stream
, offset
);
260 Sector
*sector
= new Sector
;
261 SafeRead(stream
, sector
, sizeof(Sector
));
263 assert(table
->find(offset
) == table
->end());
264 (*table
)[offset
] = sector
;
274 CowDiskImage::init(int hash_size
)
276 table
= new SectorTable(hash_size
);
282 SafeWrite(ofstream
&stream
, const void *data
, int count
)
284 stream
.write((const char *)data
, count
);
285 if (!stream
.is_open())
286 panic("file not open");
289 panic("premature end-of-file");
291 if (stream
.bad() || stream
.fail())
292 panic("error reading cowdisk image");
297 SafeWrite(ofstream
&stream
, const T
&data
)
299 SafeWrite(stream
, &data
, sizeof(data
));
304 SafeWriteSwap(ofstream
&stream
, const T
&data
)
306 T swappeddata
= letoh(data
); //is this the proper byte order conversion?
307 SafeWrite(stream
, &swappeddata
, sizeof(data
));
316 CowDiskImage::save(const string
&file
)
319 panic("RawDiskImage not initialized");
321 ofstream
stream(file
.c_str());
322 if (!stream
.is_open() || stream
.fail() || stream
.bad())
323 panic("Error opening %s", file
);
326 memcpy(&magic
, "COWDISK!", sizeof(magic
));
327 SafeWrite(stream
, magic
);
329 SafeWriteSwap(stream
, (uint32_t)VersionMajor
);
330 SafeWriteSwap(stream
, (uint32_t)VersionMinor
);
331 SafeWriteSwap(stream
, (uint64_t)table
->size());
333 uint64_t size
= table
->size();
334 SectorTable::iterator iter
= table
->begin();
335 SectorTable::iterator end
= table
->end();
337 for (uint64_t i
= 0; i
< size
; i
++) {
339 panic("Incorrect Table Size during save of COW disk image");
341 SafeWriteSwap(stream
, (uint64_t)(*iter
).first
);
342 SafeWrite(stream
, (*iter
).second
->data
, sizeof(Sector
));
350 CowDiskImage::writeback()
352 SectorTable::iterator i
= table
->begin();
353 SectorTable::iterator end
= table
->end();
356 child
->write((*i
).second
->data
, (*i
).first
);
362 CowDiskImage::size() const
363 { return child
->size(); }
366 CowDiskImage::read(uint8_t *data
, off_t offset
) const
369 panic("CowDiskImage not initialized");
372 panic("access out of bounds");
374 SectorTable::const_iterator i
= table
->find(offset
);
375 if (i
== table
->end())
376 return child
->read(data
, offset
);
378 memcpy(data
, (*i
).second
->data
, SectorSize
);
379 DPRINTF(DiskImageRead
, "read: offset=%d\n", (uint64_t)offset
);
380 DDUMP(DiskImageRead
, data
, SectorSize
);
386 CowDiskImage::write(const uint8_t *data
, off_t offset
)
389 panic("RawDiskImage not initialized");
392 panic("access out of bounds");
394 SectorTable::iterator i
= table
->find(offset
);
395 if (i
== table
->end()) {
396 Sector
*sector
= new Sector
;
397 memcpy(sector
, data
, SectorSize
);
398 table
->insert(make_pair(offset
, sector
));
400 memcpy((*i
).second
->data
, data
, SectorSize
);
403 DPRINTF(DiskImageWrite
, "write: offset=%d\n", (uint64_t)offset
);
404 DDUMP(DiskImageWrite
, data
, SectorSize
);
410 CowDiskImage::serialize(ostream
&os
)
412 string cowFilename
= name() + ".cow";
413 SERIALIZE_SCALAR(cowFilename
);
414 save(Checkpoint::dir() + "/" + cowFilename
);
418 CowDiskImage::unserialize(Checkpoint
*cp
, const string
§ion
)
421 UNSERIALIZE_SCALAR(cowFilename
);
422 cowFilename
= cp
->cptDir
+ "/" + cowFilename
;
427 CowDiskImageParams::create()
429 if (((string
)image_file
).empty())
430 return new CowDiskImage(name
, child
, table_size
);
432 return new CowDiskImage(name
, child
, table_size
,
433 image_file
, read_only
);