disk_image.cc revision 8232
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 89off_t 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 102off_t 103RawDiskImage::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 123off_t 124RawDiskImage::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 146RawDiskImage * 147RawDiskImageParams::create() 148{ 149 return new RawDiskImage(this); 150} 151 152//////////////////////////////////////////////////////////////////////// 153// 154// Copy on Write Disk image 155// 156const uint32_t CowDiskImage::VersionMajor = 1; 157const uint32_t CowDiskImage::VersionMinor = 0; 158 159class 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 169CowDiskImage::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 186CowDiskImage::~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 197void 198SafeRead(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 211template<class T> 212void 213SafeRead(ifstream &stream, T &data) 214{ 215 SafeRead(stream, &data, sizeof(data)); 216} 217 218template<class T> 219void 220SafeReadSwap(ifstream &stream, T &data) 221{ 222 SafeRead(stream, &data, sizeof(data)); 223 data = letoh(data); //is this the proper byte order conversion? 224} 225 226bool 227CowDiskImage::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 272void 273CowDiskImage::init(int hash_size) 274{ 275 table = new SectorTable(hash_size); 276 277 initialized = true; 278} 279 280void 281SafeWrite(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 294template<class T> 295void 296SafeWrite(ofstream &stream, const T &data) 297{ 298 SafeWrite(stream, &data, sizeof(data)); 299} 300 301template<class T> 302void 303SafeWriteSwap(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} 308void 309CowDiskImage::save() 310{ 311 save(filename); 312} 313 314void 315CowDiskImage::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 348void 349CowDiskImage::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 360off_t 361CowDiskImage::size() const 362{ return child->size(); } 363 364off_t 365CowDiskImage::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 384off_t 385CowDiskImage::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 408void 409CowDiskImage::serialize(ostream &os) 410{ 411 string cowFilename = name() + ".cow"; 412 SERIALIZE_SCALAR(cowFilename); 413 save(Checkpoint::dir() + "/" + cowFilename); 414} 415 416void 417CowDiskImage::unserialize(Checkpoint *cp, const string §ion) 418{ 419 string cowFilename; 420 UNSERIALIZE_SCALAR(cowFilename); 421 cowFilename = cp->cptDir + "/" + cowFilename; 422 open(cowFilename); 423} 424 425CowDiskImage * 426CowDiskImageParams::create() 427{ 428 return new CowDiskImage(this); 429} 430