disk_image.cc revision 5034
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 assert(!p->read_only && "why have a non-existent read only file?"); 175 init(p->table_size); 176 } 177 178 if (!p->read_only) 179 registerExitCallback(new CowDiskCallback(this)); 180 } 181} 182 183CowDiskImage::~CowDiskImage() 184{ 185 SectorTable::iterator i = table->begin(); 186 SectorTable::iterator end = table->end(); 187 188 while (i != end) { 189 delete (*i).second; 190 ++i; 191 } 192} 193 194void 195SafeRead(ifstream &stream, void *data, int count) 196{ 197 stream.read((char *)data, count); 198 if (!stream.is_open()) 199 panic("file not open"); 200 201 if (stream.eof()) 202 panic("premature end-of-file"); 203 204 if (stream.bad() || stream.fail()) 205 panic("error reading cowdisk image"); 206} 207 208template<class T> 209void 210SafeRead(ifstream &stream, T &data) 211{ 212 SafeRead(stream, &data, sizeof(data)); 213} 214 215template<class T> 216void 217SafeReadSwap(ifstream &stream, T &data) 218{ 219 SafeRead(stream, &data, sizeof(data)); 220 data = letoh(data); //is this the proper byte order conversion? 221} 222 223bool 224CowDiskImage::open(const string &file) 225{ 226 ifstream stream(file.c_str()); 227 if (!stream.is_open()) 228 return false; 229 230 if (stream.fail() || stream.bad()) 231 panic("Error opening %s", file); 232 233 uint64_t magic; 234 SafeRead(stream, magic); 235 236 if (memcmp(&magic, "COWDISK!", sizeof(magic)) != 0) 237 panic("Could not open %s: Invalid magic", file); 238 239 uint32_t major, minor; 240 SafeReadSwap(stream, major); 241 SafeReadSwap(stream, minor); 242 243 if (major != VersionMajor && minor != VersionMinor) 244 panic("Could not open %s: invalid version %d.%d != %d.%d", 245 file, major, minor, VersionMajor, VersionMinor); 246 247 uint64_t sector_count; 248 SafeReadSwap(stream, sector_count); 249 table = new SectorTable(sector_count); 250 251 252 for (uint64_t i = 0; i < sector_count; i++) { 253 uint64_t offset; 254 SafeReadSwap(stream, offset); 255 256 Sector *sector = new Sector; 257 SafeRead(stream, sector, sizeof(Sector)); 258 259 assert(table->find(offset) == table->end()); 260 (*table)[offset] = sector; 261 } 262 263 stream.close(); 264 265 initialized = true; 266 return true; 267} 268 269void 270CowDiskImage::init(int hash_size) 271{ 272 table = new SectorTable(hash_size); 273 274 initialized = true; 275} 276 277void 278SafeWrite(ofstream &stream, const void *data, int count) 279{ 280 stream.write((const char *)data, count); 281 if (!stream.is_open()) 282 panic("file not open"); 283 284 if (stream.eof()) 285 panic("premature end-of-file"); 286 287 if (stream.bad() || stream.fail()) 288 panic("error reading cowdisk image"); 289} 290 291template<class T> 292void 293SafeWrite(ofstream &stream, const T &data) 294{ 295 SafeWrite(stream, &data, sizeof(data)); 296} 297 298template<class T> 299void 300SafeWriteSwap(ofstream &stream, const T &data) 301{ 302 T swappeddata = letoh(data); //is this the proper byte order conversion? 303 SafeWrite(stream, &swappeddata, sizeof(data)); 304} 305void 306CowDiskImage::save() 307{ 308 save(filename); 309} 310 311void 312CowDiskImage::save(const string &file) 313{ 314 if (!initialized) 315 panic("RawDiskImage not initialized"); 316 317 ofstream stream(file.c_str()); 318 if (!stream.is_open() || stream.fail() || stream.bad()) 319 panic("Error opening %s", file); 320 321 uint64_t magic; 322 memcpy(&magic, "COWDISK!", sizeof(magic)); 323 SafeWrite(stream, magic); 324 325 SafeWriteSwap(stream, (uint32_t)VersionMajor); 326 SafeWriteSwap(stream, (uint32_t)VersionMinor); 327 SafeWriteSwap(stream, (uint64_t)table->size()); 328 329 uint64_t size = table->size(); 330 SectorTable::iterator iter = table->begin(); 331 SectorTable::iterator end = table->end(); 332 333 for (uint64_t i = 0; i < size; i++) { 334 if (iter == end) 335 panic("Incorrect Table Size during save of COW disk image"); 336 337 SafeWriteSwap(stream, (uint64_t)(*iter).first); 338 SafeWrite(stream, (*iter).second->data, sizeof(Sector)); 339 ++iter; 340 } 341 342 stream.close(); 343} 344 345void 346CowDiskImage::writeback() 347{ 348 SectorTable::iterator i = table->begin(); 349 SectorTable::iterator end = table->end(); 350 351 while (i != end) { 352 child->write((*i).second->data, (*i).first); 353 ++i; 354 } 355} 356 357off_t 358CowDiskImage::size() const 359{ return child->size(); } 360 361off_t 362CowDiskImage::read(uint8_t *data, off_t offset) const 363{ 364 if (!initialized) 365 panic("CowDiskImage not initialized"); 366 367 if (offset > size()) 368 panic("access out of bounds"); 369 370 SectorTable::const_iterator i = table->find(offset); 371 if (i == table->end()) 372 return child->read(data, offset); 373 else { 374 memcpy(data, (*i).second->data, SectorSize); 375 DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset); 376 DDUMP(DiskImageRead, data, SectorSize); 377 return SectorSize; 378 } 379} 380 381off_t 382CowDiskImage::write(const uint8_t *data, off_t offset) 383{ 384 if (!initialized) 385 panic("RawDiskImage not initialized"); 386 387 if (offset > size()) 388 panic("access out of bounds"); 389 390 SectorTable::iterator i = table->find(offset); 391 if (i == table->end()) { 392 Sector *sector = new Sector; 393 memcpy(sector, data, SectorSize); 394 table->insert(make_pair(offset, sector)); 395 } else { 396 memcpy((*i).second->data, data, SectorSize); 397 } 398 399 DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset); 400 DDUMP(DiskImageWrite, data, SectorSize); 401 402 return SectorSize; 403} 404 405void 406CowDiskImage::serialize(ostream &os) 407{ 408 string cowFilename = name() + ".cow"; 409 SERIALIZE_SCALAR(cowFilename); 410 save(Checkpoint::dir() + "/" + cowFilename); 411} 412 413void 414CowDiskImage::unserialize(Checkpoint *cp, const string §ion) 415{ 416 string cowFilename; 417 UNSERIALIZE_SCALAR(cowFilename); 418 cowFilename = cp->cptDir + "/" + cowFilename; 419 open(cowFilename); 420} 421 422CowDiskImage * 423CowDiskImageParams::create() 424{ 425 return new CowDiskImage(this); 426} 427