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