Config: Enable using O3 CPU and Ruby in SE mode
[gem5.git] / src / dev / disk_image.cc
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 * Authors: Nathan Binkert
29 */
30
31 /** @file
32 * Disk Image Definitions
33 */
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/misc.hh"
46 #include "base/trace.hh"
47 #include "debug/DiskImageRead.hh"
48 #include "debug/DiskImageWrite.hh"
49 #include "dev/disk_image.hh"
50 #include "sim/byteswap.hh"
51 #include "sim/sim_exit.hh"
52
53 using namespace std;
54
55 ////////////////////////////////////////////////////////////////////////
56 //
57 // Raw Disk image
58 //
59 RawDiskImage::RawDiskImage(const Params* p)
60 : DiskImage(p), disk_size(0)
61 { open(p->image_file, p->read_only); }
62
63 RawDiskImage::~RawDiskImage()
64 { close(); }
65
66 void
67 RawDiskImage::open(const string &filename, bool rd_only)
68 {
69 if (!filename.empty()) {
70 initialized = true;
71 readonly = rd_only;
72 file = filename;
73
74 ios::openmode mode = ios::in | ios::binary;
75 if (!readonly)
76 mode |= ios::out;
77 stream.open(file.c_str(), mode);
78 if (!stream.is_open())
79 panic("Error opening %s", filename);
80 }
81 }
82
83 void
84 RawDiskImage::close()
85 {
86 stream.close();
87 }
88
89 off_t
90 RawDiskImage::size() const
91 {
92 if (disk_size == 0) {
93 if (!stream.is_open())
94 panic("file not open!\n");
95 stream.seekg(0, ios::end);
96 disk_size = stream.tellg();
97 }
98
99 return disk_size / SectorSize;
100 }
101
102 off_t
103 RawDiskImage::read(uint8_t *data, off_t offset) const
104 {
105 if (!initialized)
106 panic("RawDiskImage not initialized");
107
108 if (!stream.is_open())
109 panic("file not open!\n");
110
111 if (stream.seekg(offset * SectorSize, ios::beg) < 0)
112 panic("Could not seek to location in file");
113
114 streampos pos = stream.tellg();
115 stream.read((char *)data, SectorSize);
116
117 DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset);
118 DDUMP(DiskImageRead, data, SectorSize);
119
120 return stream.tellg() - pos;
121 }
122
123 off_t
124 RawDiskImage::write(const uint8_t *data, off_t offset)
125 {
126 if (!initialized)
127 panic("RawDiskImage not initialized");
128
129 if (readonly)
130 panic("Cannot write to a read only disk image");
131
132 if (!stream.is_open())
133 panic("file not open!\n");
134
135 if (stream.seekp(offset * SectorSize, ios::beg) < 0)
136 panic("Could not seek to location in file");
137
138 DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset);
139 DDUMP(DiskImageWrite, data, SectorSize);
140
141 streampos pos = stream.tellp();
142 stream.write((const char *)data, SectorSize);
143 return stream.tellp() - pos;
144 }
145
146 RawDiskImage *
147 RawDiskImageParams::create()
148 {
149 return new RawDiskImage(this);
150 }
151
152 ////////////////////////////////////////////////////////////////////////
153 //
154 // Copy on Write Disk image
155 //
156 const uint32_t CowDiskImage::VersionMajor = 1;
157 const uint32_t CowDiskImage::VersionMinor = 0;
158
159 class CowDiskCallback : public Callback
160 {
161 private:
162 CowDiskImage *image;
163
164 public:
165 CowDiskCallback(CowDiskImage *i) : image(i) {}
166 void process() { image->save(); delete this; }
167 };
168
169 CowDiskImage::CowDiskImage(const Params *p)
170 : DiskImage(p), filename(p->image_file), child(p->child), table(NULL)
171 {
172 if (filename.empty()) {
173 init(p->table_size);
174 } else {
175 if (!open(filename)) {
176 if (p->read_only)
177 fatal("could not open read-only file");
178 init(p->table_size);
179 }
180
181 if (!p->read_only)
182 registerExitCallback(new CowDiskCallback(this));
183 }
184 }
185
186 CowDiskImage::~CowDiskImage()
187 {
188 SectorTable::iterator i = table->begin();
189 SectorTable::iterator end = table->end();
190
191 while (i != end) {
192 delete (*i).second;
193 ++i;
194 }
195 }
196
197 void
198 SafeRead(ifstream &stream, void *data, int count)
199 {
200 stream.read((char *)data, count);
201 if (!stream.is_open())
202 panic("file not open");
203
204 if (stream.eof())
205 panic("premature end-of-file");
206
207 if (stream.bad() || stream.fail())
208 panic("error reading cowdisk image");
209 }
210
211 template<class T>
212 void
213 SafeRead(ifstream &stream, T &data)
214 {
215 SafeRead(stream, &data, sizeof(data));
216 }
217
218 template<class T>
219 void
220 SafeReadSwap(ifstream &stream, T &data)
221 {
222 SafeRead(stream, &data, sizeof(data));
223 data = letoh(data); //is this the proper byte order conversion?
224 }
225
226 bool
227 CowDiskImage::open(const string &file)
228 {
229 ifstream stream(file.c_str());
230 if (!stream.is_open())
231 return false;
232
233 if (stream.fail() || stream.bad())
234 panic("Error opening %s", file);
235
236 uint64_t magic;
237 SafeRead(stream, magic);
238
239 if (memcmp(&magic, "COWDISK!", sizeof(magic)) != 0)
240 panic("Could not open %s: Invalid magic", file);
241
242 uint32_t major, minor;
243 SafeReadSwap(stream, major);
244 SafeReadSwap(stream, minor);
245
246 if (major != VersionMajor && minor != VersionMinor)
247 panic("Could not open %s: invalid version %d.%d != %d.%d",
248 file, major, minor, VersionMajor, VersionMinor);
249
250 uint64_t sector_count;
251 SafeReadSwap(stream, sector_count);
252 table = new SectorTable(sector_count);
253
254
255 for (uint64_t i = 0; i < sector_count; i++) {
256 uint64_t offset;
257 SafeReadSwap(stream, offset);
258
259 Sector *sector = new Sector;
260 SafeRead(stream, sector, sizeof(Sector));
261
262 assert(table->find(offset) == table->end());
263 (*table)[offset] = sector;
264 }
265
266 stream.close();
267
268 initialized = true;
269 return true;
270 }
271
272 void
273 CowDiskImage::init(int hash_size)
274 {
275 table = new SectorTable(hash_size);
276
277 initialized = true;
278 }
279
280 void
281 SafeWrite(ofstream &stream, const void *data, int count)
282 {
283 stream.write((const char *)data, count);
284 if (!stream.is_open())
285 panic("file not open");
286
287 if (stream.eof())
288 panic("premature end-of-file");
289
290 if (stream.bad() || stream.fail())
291 panic("error reading cowdisk image");
292 }
293
294 template<class T>
295 void
296 SafeWrite(ofstream &stream, const T &data)
297 {
298 SafeWrite(stream, &data, sizeof(data));
299 }
300
301 template<class T>
302 void
303 SafeWriteSwap(ofstream &stream, const T &data)
304 {
305 T swappeddata = letoh(data); //is this the proper byte order conversion?
306 SafeWrite(stream, &swappeddata, sizeof(data));
307 }
308 void
309 CowDiskImage::save()
310 {
311 save(filename);
312 }
313
314 void
315 CowDiskImage::save(const string &file)
316 {
317 if (!initialized)
318 panic("RawDiskImage not initialized");
319
320 ofstream stream(file.c_str());
321 if (!stream.is_open() || stream.fail() || stream.bad())
322 panic("Error opening %s", file);
323
324 uint64_t magic;
325 memcpy(&magic, "COWDISK!", sizeof(magic));
326 SafeWrite(stream, magic);
327
328 SafeWriteSwap(stream, (uint32_t)VersionMajor);
329 SafeWriteSwap(stream, (uint32_t)VersionMinor);
330 SafeWriteSwap(stream, (uint64_t)table->size());
331
332 uint64_t size = table->size();
333 SectorTable::iterator iter = table->begin();
334 SectorTable::iterator end = table->end();
335
336 for (uint64_t i = 0; i < size; i++) {
337 if (iter == end)
338 panic("Incorrect Table Size during save of COW disk image");
339
340 SafeWriteSwap(stream, (uint64_t)(*iter).first);
341 SafeWrite(stream, (*iter).second->data, sizeof(Sector));
342 ++iter;
343 }
344
345 stream.close();
346 }
347
348 void
349 CowDiskImage::writeback()
350 {
351 SectorTable::iterator i = table->begin();
352 SectorTable::iterator end = table->end();
353
354 while (i != end) {
355 child->write((*i).second->data, (*i).first);
356 ++i;
357 }
358 }
359
360 off_t
361 CowDiskImage::size() const
362 { return child->size(); }
363
364 off_t
365 CowDiskImage::read(uint8_t *data, off_t offset) const
366 {
367 if (!initialized)
368 panic("CowDiskImage not initialized");
369
370 if (offset > size())
371 panic("access out of bounds");
372
373 SectorTable::const_iterator i = table->find(offset);
374 if (i == table->end())
375 return child->read(data, offset);
376 else {
377 memcpy(data, (*i).second->data, SectorSize);
378 DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset);
379 DDUMP(DiskImageRead, data, SectorSize);
380 return SectorSize;
381 }
382 }
383
384 off_t
385 CowDiskImage::write(const uint8_t *data, off_t offset)
386 {
387 if (!initialized)
388 panic("RawDiskImage not initialized");
389
390 if (offset > size())
391 panic("access out of bounds");
392
393 SectorTable::iterator i = table->find(offset);
394 if (i == table->end()) {
395 Sector *sector = new Sector;
396 memcpy(sector, data, SectorSize);
397 table->insert(make_pair(offset, sector));
398 } else {
399 memcpy((*i).second->data, data, SectorSize);
400 }
401
402 DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset);
403 DDUMP(DiskImageWrite, data, SectorSize);
404
405 return SectorSize;
406 }
407
408 void
409 CowDiskImage::serialize(ostream &os)
410 {
411 string cowFilename = name() + ".cow";
412 SERIALIZE_SCALAR(cowFilename);
413 save(Checkpoint::dir() + "/" + cowFilename);
414 }
415
416 void
417 CowDiskImage::unserialize(Checkpoint *cp, const string &section)
418 {
419 string cowFilename;
420 UNSERIALIZE_SCALAR(cowFilename);
421 cowFilename = cp->cptDir + "/" + cowFilename;
422 open(cowFilename);
423 }
424
425 CowDiskImage *
426 CowDiskImageParams::create()
427 {
428 return new CowDiskImage(this);
429 }