2 * Copyright (c) 2003 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 <sys/types.h>
43 #include "disk_image.hh"
46 #include "sim_exit.hh"
47 #include "callback.hh"
51 ////////////////////////////////////////////////////////////////////////
55 RawDiskImage::RawDiskImage(const string
&name
, const string
&filename
,
57 : DiskImage(name
), disk_size(0)
58 { open(filename
, rd_only
); }
60 RawDiskImage::~RawDiskImage()
64 RawDiskImage::open(const string
&filename
, bool rd_only
)
66 if (!filename
.empty()) {
71 ios::openmode mode
= ios::in
| ios::binary
;
74 stream
.open(file
.c_str(), mode
);
75 if (!stream
.is_open())
76 panic("Error opening %s", filename
);
87 RawDiskImage::size() const
90 if (!stream
.is_open())
91 panic("file not open!\n");
92 stream
.seekg(0, ios::end
);
93 disk_size
= stream
.tellg();
96 return disk_size
/ SectorSize
;
100 RawDiskImage::read(uint8_t *data
, off_t offset
) const
103 panic("RawDiskImage not initialized");
105 if (!stream
.is_open())
106 panic("file not open!\n");
108 if (stream
.seekg(offset
* SectorSize
, ios::beg
) < 0)
109 panic("Could not seek to location in file");
111 off_t pos
= stream
.tellg();
112 stream
.read((char *)data
, SectorSize
);
114 DPRINTF(DiskImageRead
, "read: offset=%d\n", (uint64_t)offset
);
115 DDUMP(DiskImageRead
, data
, SectorSize
);
117 return stream
.tellg() - pos
;
121 RawDiskImage::write(const uint8_t *data
, off_t offset
)
124 panic("RawDiskImage not initialized");
127 panic("Cannot write to a read only disk image");
129 if (!stream
.is_open())
130 panic("file not open!\n");
132 if (stream
.seekp(offset
* SectorSize
, ios::beg
) < 0)
133 panic("Could not seek to location in file");
135 DPRINTF(DiskImageWrite
, "write: offset=%d\n", (uint64_t)offset
);
136 DDUMP(DiskImageWrite
, data
, SectorSize
);
138 off_t pos
= stream
.tellp();
139 stream
.write((const char *)data
, SectorSize
);
140 return stream
.tellp() - pos
;
143 DEFINE_SIM_OBJECT_CLASS_NAME("DiskImage", DiskImage
)
145 BEGIN_DECLARE_SIM_OBJECT_PARAMS(RawDiskImage
)
147 Param
<string
> image_file
;
148 Param
<bool> read_only
;
150 END_DECLARE_SIM_OBJECT_PARAMS(RawDiskImage
)
152 BEGIN_INIT_SIM_OBJECT_PARAMS(RawDiskImage
)
154 INIT_PARAM(image_file
, "disk image file"),
155 INIT_PARAM_DFLT(read_only
, "read only image", false)
157 END_INIT_SIM_OBJECT_PARAMS(RawDiskImage
)
160 CREATE_SIM_OBJECT(RawDiskImage
)
162 return new RawDiskImage(getInstanceName(), image_file
, read_only
);
165 REGISTER_SIM_OBJECT("RawDiskImage", RawDiskImage
)
167 ////////////////////////////////////////////////////////////////////////
169 // Copy on Write Disk image
171 const int CowDiskImage::VersionMajor
= 1;
172 const int CowDiskImage::VersionMinor
= 0;
174 CowDiskImage::CowDiskImage(const string
&name
, DiskImage
*kid
, int hash_size
)
175 : DiskImage(name
), child(kid
), table(NULL
)
178 class CowDiskCallback
: public Callback
184 CowDiskCallback(CowDiskImage
*i
) : image(i
) {}
185 void process() { image
->save(); delete this; }
188 CowDiskImage::CowDiskImage(const string
&name
, DiskImage
*kid
, int hash_size
,
189 const string
&file
, bool read_only
)
190 : DiskImage(name
), filename(file
), child(kid
), table(NULL
)
193 assert(!read_only
&& "why have a non-existent read only file?");
198 registerExitCallback(new CowDiskCallback(this));
201 CowDiskImage::~CowDiskImage()
203 SectorTable::iterator i
= table
->begin();
204 SectorTable::iterator end
= table
->end();
213 SafeRead(ifstream
&stream
, void *data
, int count
)
215 stream
.read((char *)data
, count
);
216 if (!stream
.is_open())
217 panic("file not open");
220 panic("premature end-of-file");
222 if (stream
.bad() || stream
.fail())
223 panic("error reading cowdisk image");
228 SafeRead(ifstream
&stream
, T
&data
)
229 { SafeRead(stream
, &data
, sizeof(data
)); }
234 ifstream
stream(filename
.c_str());
235 if (!stream
.is_open())
238 if (stream
.fail() || stream
.bad())
239 panic("Error opening %s", filename
);
242 SafeRead(stream
, magic
);
244 if (memcmp(&magic
, "COWDISK!", sizeof(magic
)) != 0)
245 panic("Could not open %s: Invalid magic", filename
);
247 uint32_t major
, minor
;
248 SafeRead(stream
, major
);
249 SafeRead(stream
, minor
);
251 if (major
!= VersionMajor
&& minor
!= VersionMinor
)
252 panic("Could not open %s: invalid version %d.%d != %d.%d",
253 filename
, major
, minor
, VersionMajor
, VersionMinor
);
255 uint64_t sector_count
;
256 SafeRead(stream
, sector_count
);
257 table
= new SectorTable(sector_count
);
260 for (uint64_t i
= 0; i
< sector_count
; i
++) {
262 SafeRead(stream
, offset
);
264 Sector
*sector
= new Sector
;
265 SafeRead(stream
, sector
, sizeof(Sector
));
267 assert(table
->find(offset
) == table
->end());
268 (*table
)[offset
] = sector
;
278 CowDiskImage::init(int hash_size
)
280 table
= new SectorTable(hash_size
);
286 SafeWrite(ofstream
&stream
, const void *data
, int count
)
288 stream
.write((const char *)data
, count
);
289 if (!stream
.is_open())
290 panic("file not open");
293 panic("premature end-of-file");
295 if (stream
.bad() || stream
.fail())
296 panic("error reading cowdisk image");
301 SafeWrite(ofstream
&stream
, const T
&data
)
302 { SafeWrite(stream
, &data
, sizeof(data
)); }
308 panic("RawDiskImage not initialized");
310 ofstream
stream(filename
.c_str());
311 if (!stream
.is_open() || stream
.fail() || stream
.bad())
312 panic("Error opening %s", filename
);
315 memcpy(&magic
, "COWDISK!", sizeof(magic
));
316 SafeWrite(stream
, magic
);
318 SafeWrite(stream
, (uint32_t)VersionMajor
);
319 SafeWrite(stream
, (uint32_t)VersionMinor
);
320 SafeWrite(stream
, (uint64_t)table
->size());
322 uint64_t size
= table
->size();
323 SectorTable::iterator iter
= table
->begin();
324 SectorTable::iterator end
= table
->end();
326 for (uint64_t i
= 0; i
< size
; i
++) {
328 panic("Incorrect Table Size during save of COW disk image");
330 SafeWrite(stream
, (uint64_t)(*iter
).first
);
331 SafeWrite(stream
, (*iter
).second
->data
, sizeof(Sector
));
339 CowDiskImage::writeback()
341 SectorTable::iterator i
= table
->begin();
342 SectorTable::iterator end
= table
->end();
345 child
->write((*i
).second
->data
, (*i
).first
);
351 CowDiskImage::size() const
352 { return child
->size(); }
355 CowDiskImage::read(uint8_t *data
, off_t offset
) const
358 panic("CowDiskImage not initialized");
361 panic("access out of bounds");
363 SectorTable::const_iterator i
= table
->find(offset
);
364 if (i
== table
->end())
365 return child
->read(data
, offset
);
367 memcpy(data
, (*i
).second
->data
, SectorSize
);
368 DPRINTF(DiskImageRead
, "read: offset=%d\n", (uint64_t)offset
);
369 DDUMP(DiskImageRead
, data
, SectorSize
);
375 CowDiskImage::write(const uint8_t *data
, off_t offset
)
378 panic("RawDiskImage not initialized");
381 panic("access out of bounds");
383 SectorTable::iterator i
= table
->find(offset
);
384 if (i
== table
->end()) {
385 Sector
*sector
= new Sector
;
386 memcpy(sector
, data
, SectorSize
);
387 table
->insert(make_pair(offset
, sector
));
389 memcpy((*i
).second
->data
, data
, SectorSize
);
392 DPRINTF(DiskImageWrite
, "write: offset=%d\n", (uint64_t)offset
);
393 DDUMP(DiskImageWrite
, data
, SectorSize
);
398 BEGIN_DECLARE_SIM_OBJECT_PARAMS(CowDiskImage
)
400 SimObjectParam
<DiskImage
*> child
;
401 Param
<string
> image_file
;
402 Param
<int> table_size
;
403 Param
<bool> read_only
;
405 END_DECLARE_SIM_OBJECT_PARAMS(CowDiskImage
)
407 BEGIN_INIT_SIM_OBJECT_PARAMS(CowDiskImage
)
409 INIT_PARAM(child
, "child image"),
410 INIT_PARAM_DFLT(image_file
, "disk image file", ""),
411 INIT_PARAM_DFLT(table_size
, "initial table size", 65536),
412 INIT_PARAM_DFLT(read_only
, "don't write back to the copy-on-write file",
415 END_INIT_SIM_OBJECT_PARAMS(CowDiskImage
)
418 CREATE_SIM_OBJECT(CowDiskImage
)
420 if (((string
)image_file
).empty())
421 return new CowDiskImage(getInstanceName(), child
, table_size
);
423 return new CowDiskImage(getInstanceName(), child
, table_size
,
424 image_file
, read_only
);
427 REGISTER_SIM_OBJECT("CowDiskImage", CowDiskImage
)