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