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