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 &section)
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