disk_image.cc revision 1722
11060SN/A/* 21762SN/A * Copyright (c) 2001-2004 The Regents of The University of Michigan 31060SN/A * All rights reserved. 41060SN/A * 51060SN/A * Redistribution and use in source and binary forms, with or without 61060SN/A * modification, are permitted provided that the following conditions are 71060SN/A * met: redistributions of source code must retain the above copyright 81060SN/A * notice, this list of conditions and the following disclaimer; 91060SN/A * redistributions in binary form must reproduce the above copyright 101060SN/A * notice, this list of conditions and the following disclaimer in the 111060SN/A * documentation and/or other materials provided with the distribution; 121060SN/A * neither the name of the copyright holders nor the names of its 131060SN/A * contributors may be used to endorse or promote products derived from 141060SN/A * this software without specific prior written permission. 151060SN/A * 161060SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 171060SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 181060SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 191060SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 201060SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 211060SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 221060SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 231060SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 241060SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 251060SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 261060SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu */ 282665Ssaidi@eecs.umich.edu 291060SN/A/** @file 301060SN/A * Disk Image Definitions 311464SN/A */ 321464SN/A 331060SN/A#include <sys/types.h> 342292SN/A#include <sys/uio.h> 351464SN/A#include <errno.h> 361060SN/A#include <unistd.h> 372669Sktlim@umich.edu 381060SN/A#include <cstdio> 391060SN/A#include <cstring> 401858SN/A#include <fstream> 411464SN/A#include <string> 421464SN/A 432669Sktlim@umich.edu#include "base/callback.hh" 441060SN/A#include "base/misc.hh" 452669Sktlim@umich.edu#include "base/trace.hh" 462292SN/A#include "dev/disk_image.hh" 472292SN/A#include "sim/builder.hh" 481717SN/A#include "sim/sim_exit.hh" 491717SN/A#include "targetarch/byte_swap.hh" 501717SN/A 511717SN/Ausing namespace std; 522292SN/A 531060SN/A//////////////////////////////////////////////////////////////////////// 541060SN/A// 551060SN/A// Raw Disk image 561060SN/A// 571060SN/ARawDiskImage::RawDiskImage(const string &name, const string &filename, 581060SN/A bool rd_only) 591061SN/A : DiskImage(name), disk_size(0) 601061SN/A{ open(filename, rd_only); } 611060SN/A 621060SN/ARawDiskImage::~RawDiskImage() 631061SN/A{ close(); } 641060SN/A 651060SN/Avoid 661060SN/ARawDiskImage::open(const string &filename, bool rd_only) 671060SN/A{ 682292SN/A if (!filename.empty()) { 691060SN/A initialized = true; 702292SN/A readonly = rd_only; 712107SN/A file = filename; 722292SN/A 732292SN/A ios::openmode mode = ios::in | ios::binary; 742292SN/A if (!readonly) 752107SN/A mode |= ios::out; 762690Sktlim@umich.edu stream.open(file.c_str(), mode); 772107SN/A if (!stream.is_open()) 782690Sktlim@umich.edu panic("Error opening %s", filename); 792690Sktlim@umich.edu } 801060SN/A} 812292SN/A 822292SN/Avoid 832292SN/ARawDiskImage::close() 842292SN/A{ 852292SN/A stream.close(); 862292SN/A} 871060SN/A 882292SN/Aoff_t 892292SN/ARawDiskImage::size() const 901060SN/A{ 911060SN/A if (disk_size == 0) { 922292SN/A if (!stream.is_open()) 932107SN/A panic("file not open!\n"); 941060SN/A stream.seekg(0, ios::end); 951060SN/A disk_size = stream.tellg(); 961060SN/A } 971060SN/A 981060SN/A return disk_size / SectorSize; 991060SN/A} 1002292SN/A 1011060SN/Aoff_t 1021060SN/ARawDiskImage::read(uint8_t *data, off_t offset) const 1032292SN/A{ 1042292SN/A if (!initialized) 1052292SN/A panic("RawDiskImage not initialized"); 1062292SN/A 1072292SN/A if (!stream.is_open()) 1082292SN/A panic("file not open!\n"); 1092292SN/A 1101060SN/A if (stream.seekg(offset * SectorSize, ios::beg) < 0) 1112132SN/A panic("Could not seek to location in file"); 1121060SN/A 1132292SN/A streampos pos = stream.tellg(); 1142292SN/A stream.read((char *)data, SectorSize); 1152292SN/A 1162292SN/A DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset); 1172292SN/A DDUMP(DiskImageRead, data, SectorSize); 1182292SN/A 1192292SN/A return stream.tellg() - pos; 1202292SN/A} 1211060SN/A 1222132SN/Aoff_t 1231060SN/ARawDiskImage::write(const uint8_t *data, off_t offset) 1241060SN/A{ 1251060SN/A if (!initialized) 1261060SN/A panic("RawDiskImage not initialized"); 1272132SN/A 1282132SN/A if (readonly) 1291060SN/A panic("Cannot write to a read only disk image"); 1301684SN/A 1311060SN/A if (!stream.is_open()) 1321060SN/A panic("file not open!\n"); 1331060SN/A 1341060SN/A if (stream.seekp(offset * SectorSize, ios::beg) < 0) 1352292SN/A panic("Could not seek to location in file"); 1362292SN/A 1372292SN/A DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset); 1382292SN/A DDUMP(DiskImageWrite, data, SectorSize); 1392292SN/A 1402292SN/A streampos pos = stream.tellp(); 1412292SN/A stream.write((const char *)data, SectorSize); 1422292SN/A return stream.tellp() - pos; 1431060SN/A} 1441464SN/A 1451464SN/ADEFINE_SIM_OBJECT_CLASS_NAME("DiskImage", DiskImage) 1461464SN/A 1472308SN/ABEGIN_DECLARE_SIM_OBJECT_PARAMS(RawDiskImage) 1482308SN/A 1492308SN/A Param<string> image_file; 1501060SN/A Param<bool> read_only; 1511060SN/A 1521060SN/AEND_DECLARE_SIM_OBJECT_PARAMS(RawDiskImage) 1531060SN/A 1541060SN/ABEGIN_INIT_SIM_OBJECT_PARAMS(RawDiskImage) 1551060SN/A 1561060SN/A INIT_PARAM(image_file, "disk image file"), 1571060SN/A INIT_PARAM_DFLT(read_only, "read only image", false) 1581060SN/A 1591060SN/AEND_INIT_SIM_OBJECT_PARAMS(RawDiskImage) 1601060SN/A 1611060SN/A 1622292SN/ACREATE_SIM_OBJECT(RawDiskImage) 1632292SN/A{ 1642292SN/A return new RawDiskImage(getInstanceName(), image_file, read_only); 1651060SN/A} 1661060SN/A 1671060SN/AREGISTER_SIM_OBJECT("RawDiskImage", RawDiskImage) 1681060SN/A 1691060SN/A//////////////////////////////////////////////////////////////////////// 1701060SN/A// 1712292SN/A// Copy on Write Disk image 1722292SN/A// 1732292SN/Aconst int CowDiskImage::VersionMajor = 1; 1742292SN/Aconst int CowDiskImage::VersionMinor = 0; 1752292SN/A 1762292SN/ACowDiskImage::CowDiskImage(const string &name, DiskImage *kid, int hash_size) 1771060SN/A : DiskImage(name), child(kid), table(NULL) 1781060SN/A{ init(hash_size); } 1791060SN/A 1801060SN/Aclass CowDiskCallback : public Callback 1811060SN/A{ 1821060SN/A private: 1831060SN/A CowDiskImage *image; 1841060SN/A 1851060SN/A public: 1861060SN/A CowDiskCallback(CowDiskImage *i) : image(i) {} 1871060SN/A void process() { image->save(); delete this; } 1881060SN/A}; 1891060SN/A 1901060SN/ACowDiskImage::CowDiskImage(const string &name, DiskImage *kid, int hash_size, 1911060SN/A const string &file, bool read_only) 1922292SN/A : DiskImage(name), filename(file), child(kid), table(NULL) 1932292SN/A{ 1942292SN/A if (!open(filename)) { 1951060SN/A assert(!read_only && "why have a non-existent read only file?"); 1961060SN/A init(hash_size); 1971060SN/A } 1982680Sktlim@umich.edu 1992292SN/A if (!read_only) 2001060SN/A registerExitCallback(new CowDiskCallback(this)); 2011060SN/A} 2022132SN/A 2031060SN/ACowDiskImage::~CowDiskImage() 2042292SN/A{ 2052669Sktlim@umich.edu SectorTable::iterator i = table->begin(); 2062669Sktlim@umich.edu SectorTable::iterator end = table->end(); 2072669Sktlim@umich.edu 2082669Sktlim@umich.edu while (i != end) { 2092669Sktlim@umich.edu delete (*i).second; 2102292SN/A ++i; 2111060SN/A } 2121060SN/A} 2131060SN/A 2141060SN/Avoid 2151060SN/ASafeRead(ifstream &stream, void *data, int count) 2161060SN/A{ 2171060SN/A stream.read((char *)data, count); 2181060SN/A if (!stream.is_open()) 2191060SN/A panic("file not open"); 2201060SN/A 2211060SN/A if (stream.eof()) 2221060SN/A panic("premature end-of-file"); 2231060SN/A 2241060SN/A if (stream.bad() || stream.fail()) 2251060SN/A panic("error reading cowdisk image"); 2261060SN/A} 2271060SN/A 2281060SN/Atemplate<class T> 2291060SN/Avoid 2301060SN/ASafeRead(ifstream &stream, T &data) 2311060SN/A{ 2321464SN/A SafeRead(stream, &data, sizeof(data)); 2331464SN/A} 2341464SN/A 2351464SN/Atemplate<class T> 2361464SN/Avoid 2371060SN/ASafeReadSwap(ifstream &stream, T &data) 2381464SN/A{ 2391464SN/A SafeRead(stream, &data, sizeof(data)); 2401464SN/A data = htoa(data); 2411464SN/A} 2421060SN/A 2431060SN/Abool 2441060SN/ACowDiskImage::open(const string &file) 2451060SN/A{ 2461060SN/A ifstream stream(file.c_str()); 2471060SN/A if (!stream.is_open()) 2481060SN/A return false; 2491060SN/A 2501060SN/A if (stream.fail() || stream.bad()) 2511060SN/A panic("Error opening %s", file); 2521060SN/A 2531060SN/A uint64_t magic; 2541060SN/A SafeRead(stream, magic); 2551060SN/A 2561060SN/A if (memcmp(&magic, "COWDISK!", sizeof(magic)) != 0) 2571060SN/A panic("Could not open %s: Invalid magic", file); 2582292SN/A 2592292SN/A uint32_t major, minor; 2602292SN/A SafeReadSwap(stream, major); 2612292SN/A SafeReadSwap(stream, minor); 2622292SN/A 2632292SN/A if (major != VersionMajor && minor != VersionMinor) 2641060SN/A panic("Could not open %s: invalid version %d.%d != %d.%d", 2651060SN/A file, major, minor, VersionMajor, VersionMinor); 2661060SN/A 2671060SN/A uint64_t sector_count; 2682292SN/A SafeReadSwap(stream, sector_count); 2692292SN/A table = new SectorTable(sector_count); 2702292SN/A 2712292SN/A 2722292SN/A for (uint64_t i = 0; i < sector_count; i++) { 2732292SN/A uint64_t offset; 2742292SN/A SafeReadSwap(stream, offset); 2752292SN/A 2761060SN/A Sector *sector = new Sector; 2771060SN/A SafeRead(stream, sector, sizeof(Sector)); 2782292SN/A 2792292SN/A assert(table->find(offset) == table->end()); 2802292SN/A (*table)[offset] = sector; 2812107SN/A } 2821060SN/A 2831060SN/A stream.close(); 2841060SN/A 2851060SN/A initialized = true; 2861464SN/A return true; 2871684SN/A} 2881464SN/A 2891060SN/Avoid 2901464SN/ACowDiskImage::init(int hash_size) 2912292SN/A{ 2922292SN/A table = new SectorTable(hash_size); 2932292SN/A 2942292SN/A initialized = true; 2952292SN/A} 2962292SN/A 2972292SN/Avoid 2982292SN/ASafeWrite(ofstream &stream, const void *data, int count) 2992669Sktlim@umich.edu{ 3002669Sktlim@umich.edu stream.write((const char *)data, count); 3012669Sktlim@umich.edu if (!stream.is_open()) 3022669Sktlim@umich.edu panic("file not open"); 3032669Sktlim@umich.edu 3042669Sktlim@umich.edu if (stream.eof()) 3051060SN/A panic("premature end-of-file"); 3061060SN/A 3071060SN/A if (stream.bad() || stream.fail()) 3081060SN/A panic("error reading cowdisk image"); 3091060SN/A} 3101060SN/A 3111060SN/Atemplate<class T> 3121060SN/Avoid 3132132SN/ASafeWrite(ofstream &stream, const T &data) 3141060SN/A{ 3151060SN/A SafeWrite(stream, &data, sizeof(data)); 3161060SN/A} 3171060SN/A 3182292SN/Atemplate<class T> 3191060SN/Avoid 3201060SN/ASafeWriteSwap(ofstream &stream, const T &data) 3211060SN/A{ 3221684SN/A T swappeddata = htoa(data); 3231684SN/A SafeWrite(stream, &swappeddata, sizeof(data)); 3241684SN/A} 3251060SN/Avoid 3261060SN/ACowDiskImage::save() 3271060SN/A{ 3281060SN/A save(filename); 3291060SN/A} 3301060SN/A 3311060SN/Avoid 3321060SN/ACowDiskImage::save(const string &file) 3331060SN/A{ 3342292SN/A if (!initialized) 3351060SN/A panic("RawDiskImage not initialized"); 3361060SN/A 3372292SN/A ofstream stream(file.c_str()); 3381060SN/A if (!stream.is_open() || stream.fail() || stream.bad()) 3391060SN/A panic("Error opening %s", file); 3401060SN/A 3411060SN/A uint64_t magic; 3421060SN/A memcpy(&magic, "COWDISK!", sizeof(magic)); 3431060SN/A SafeWrite(stream, magic); 3441060SN/A 3451060SN/A SafeWriteSwap(stream, (uint32_t)VersionMajor); 3462336SN/A SafeWriteSwap(stream, (uint32_t)VersionMinor); 3472336SN/A SafeWriteSwap(stream, (uint64_t)table->size()); 3481060SN/A 3491060SN/A uint64_t size = table->size(); 3501060SN/A SectorTable::iterator iter = table->begin(); 3511060SN/A SectorTable::iterator end = table->end(); 3521060SN/A 3531060SN/A for (uint64_t i = 0; i < size; i++) { 3541060SN/A if (iter == end) 3551060SN/A panic("Incorrect Table Size during save of COW disk image"); 3561060SN/A 3571060SN/A SafeWriteSwap(stream, (uint64_t)(*iter).first); 3581060SN/A SafeWrite(stream, (*iter).second->data, sizeof(Sector)); 3591060SN/A ++iter; 3601060SN/A } 3611060SN/A 3622292SN/A stream.close(); 3632292SN/A} 3642292SN/A 3652292SN/Avoid 3661060SN/ACowDiskImage::writeback() 3671060SN/A{ 3681060SN/A SectorTable::iterator i = table->begin(); 3692292SN/A SectorTable::iterator end = table->end(); 3702336SN/A 3712308SN/A while (i != end) { 3722292SN/A child->write((*i).second->data, (*i).first); 3732292SN/A ++i; 3742292SN/A } 3752292SN/A} 3762292SN/A 3772292SN/Aoff_t 3782292SN/ACowDiskImage::size() const 3792292SN/A{ return child->size(); } 3802292SN/A 3812292SN/Aoff_t 3822292SN/ACowDiskImage::read(uint8_t *data, off_t offset) const 3832292SN/A{ 3842292SN/A if (!initialized) 3852292SN/A panic("CowDiskImage not initialized"); 3862292SN/A 3872292SN/A if (offset > size()) 3882292SN/A panic("access out of bounds"); 3892292SN/A 3902292SN/A SectorTable::const_iterator i = table->find(offset); 3912292SN/A if (i == table->end()) 3922292SN/A return child->read(data, offset); 3932292SN/A else { 3942292SN/A memcpy(data, (*i).second->data, SectorSize); 3952292SN/A DPRINTF(DiskImageRead, "read: offset=%d\n", (uint64_t)offset); 3962292SN/A DDUMP(DiskImageRead, data, SectorSize); 3972292SN/A return SectorSize; 3982292SN/A } 3992292SN/A} 4002292SN/A 4012292SN/Aoff_t 4022292SN/ACowDiskImage::write(const uint8_t *data, off_t offset) 4032292SN/A{ 4042292SN/A if (!initialized) 4052292SN/A panic("RawDiskImage not initialized"); 4062292SN/A 4072292SN/A if (offset > size()) 4082292SN/A panic("access out of bounds"); 4091060SN/A 4101464SN/A SectorTable::iterator i = table->find(offset); 4111464SN/A if (i == table->end()) { 4121464SN/A Sector *sector = new Sector; 4131464SN/A memcpy(sector, data, SectorSize); 4141464SN/A table->insert(make_pair(offset, sector)); 4151464SN/A } else { 4162292SN/A memcpy((*i).second->data, data, SectorSize); 4172292SN/A } 4181684SN/A 4192292SN/A DPRINTF(DiskImageWrite, "write: offset=%d\n", (uint64_t)offset); 4201060SN/A DDUMP(DiskImageWrite, data, SectorSize); 4211060SN/A 4221060SN/A return SectorSize; 4231060SN/A} 4241060SN/A 4251060SN/Avoid 4261060SN/ACowDiskImage::serialize(ostream &os) 4271060SN/A{ 4282292SN/A string cowFilename = name() + ".cow"; 4291060SN/A SERIALIZE_SCALAR(cowFilename); 4301060SN/A save(Checkpoint::dir() + "/" + cowFilename); 4312292SN/A} 4321060SN/A 4331684SN/Avoid 4341464SN/ACowDiskImage::unserialize(Checkpoint *cp, const string §ion) 4351684SN/A{ 4361684SN/A string cowFilename; 4371464SN/A UNSERIALIZE_SCALAR(cowFilename); 4381684SN/A cowFilename = cp->cptDir + "/" + cowFilename; 4391684SN/A open(cowFilename); 4401464SN/A} 4411060SN/A 4422308SN/ABEGIN_DECLARE_SIM_OBJECT_PARAMS(CowDiskImage) 4431060SN/A 4442308SN/A SimObjectParam<DiskImage *> child; 4451060SN/A Param<string> image_file; 4461060SN/A Param<int> table_size; 4472690Sktlim@umich.edu Param<bool> read_only; 4482690Sktlim@umich.edu 4492690Sktlim@umich.eduEND_DECLARE_SIM_OBJECT_PARAMS(CowDiskImage) 4502690Sktlim@umich.edu 4512690Sktlim@umich.eduBEGIN_INIT_SIM_OBJECT_PARAMS(CowDiskImage) 4522690Sktlim@umich.edu 4532690Sktlim@umich.edu INIT_PARAM(child, "child image"), 4542690Sktlim@umich.edu INIT_PARAM_DFLT(image_file, "disk image file", ""), 4552690Sktlim@umich.edu INIT_PARAM_DFLT(table_size, "initial table size", 65536), 4562690Sktlim@umich.edu INIT_PARAM_DFLT(read_only, "don't write back to the copy-on-write file", 4572690Sktlim@umich.edu true) 4581060SN/A 4592308SN/AEND_INIT_SIM_OBJECT_PARAMS(CowDiskImage) 4602308SN/A 4611060SN/A 4622690Sktlim@umich.eduCREATE_SIM_OBJECT(CowDiskImage) 4632308SN/A{ 4642690Sktlim@umich.edu if (((string)image_file).empty()) 4652308SN/A return new CowDiskImage(getInstanceName(), child, table_size); 4661060SN/A else 4672690Sktlim@umich.edu return new CowDiskImage(getInstanceName(), child, table_size, 4682308SN/A image_file, read_only); 4692308SN/A} 4701060SN/A 4711060SN/AREGISTER_SIM_OBJECT("CowDiskImage", CowDiskImage) 4722190SN/A