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