disk_image.cc revision 5035
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 51using namespace std; 52 53//////////////////////////////////////////////////////////////////////// 54// 55// Raw Disk image 56// 57RawDiskImage::RawDiskImage(const Params* p) 58 : DiskImage(p), disk_size(0) 59{ open(p->image_file, p->read_only); } 60 61RawDiskImage::~RawDiskImage() 62{ close(); } 63 64void 65RawDiskImage::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 81void 82RawDiskImage::close() 83{ 84 stream.close(); 85} 86 87off_t 88RawDiskImage::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 100off_t 101RawDiskImage::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 121off_t 122RawDiskImage::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 144RawDiskImage * 145RawDiskImageParams::create() 146{ 147 return new RawDiskImage(this); 148} 149 150//////////////////////////////////////////////////////////////////////// 151// 152// Copy on Write Disk image 153// 154const int CowDiskImage::VersionMajor = 1; 155const int CowDiskImage::VersionMinor = 0; 156 157class 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 167CowDiskImage::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 184CowDiskImage::~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 195void 196SafeRead(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 209template<class T> 210void 211SafeRead(ifstream &stream, T &data) 212{ 213 SafeRead(stream, &data, sizeof(data)); 214} 215 216template<class T> 217void 218SafeReadSwap(ifstream &stream, T &data) 219{ 220 SafeRead(stream, &data, sizeof(data)); 221 data = letoh(data); //is this the proper byte order conversion? 222} 223 224bool 225CowDiskImage::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 270void 271CowDiskImage::init(int hash_size) 272{ 273 table = new SectorTable(hash_size); 274 275 initialized = true; 276} 277 278void 279SafeWrite(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 292template<class T> 293void 294SafeWrite(ofstream &stream, const T &data) 295{ 296 SafeWrite(stream, &data, sizeof(data)); 297} 298 299template<class T> 300void 301SafeWriteSwap(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} 306void 307CowDiskImage::save() 308{ 309 save(filename); 310} 311 312void 313CowDiskImage::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 346void 347CowDiskImage::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 358off_t 359CowDiskImage::size() const 360{ return child->size(); } 361 362off_t 363CowDiskImage::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 382off_t 383CowDiskImage::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 406void 407CowDiskImage::serialize(ostream &os) 408{ 409 string cowFilename = name() + ".cow"; 410 SERIALIZE_SCALAR(cowFilename); 411 save(Checkpoint::dir() + "/" + cowFilename); 412} 413 414void 415CowDiskImage::unserialize(Checkpoint *cp, const string §ion) 416{ 417 string cowFilename; 418 UNSERIALIZE_SCALAR(cowFilename); 419 cowFilename = cp->cptDir + "/" + cowFilename; 420 open(cowFilename); 421} 422 423CowDiskImage * 424CowDiskImageParams::create() 425{ 426 return new CowDiskImage(this); 427} 428