fs9p.cc revision 12187
13536Sgblack@eecs.umich.edu/*
23536Sgblack@eecs.umich.edu * Copyright (c) 2014-2017 ARM Limited
33536Sgblack@eecs.umich.edu * All rights reserved
43536Sgblack@eecs.umich.edu *
53536Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall
63536Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual
73536Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating
83536Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software
93536Sgblack@eecs.umich.edu * licensed hereunder.  You may use the software subject to the license
103536Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated
113536Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software,
123536Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form.
133536Sgblack@eecs.umich.edu *
143536Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
153536Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
163536Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
173536Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
183536Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
193536Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
203536Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
213536Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
223536Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
233536Sgblack@eecs.umich.edu * this software without specific prior written permission.
243536Sgblack@eecs.umich.edu *
253536Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
263536Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
273536Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
283536Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
293536Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
303536Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
313536Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
323536Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
335543Ssaidi@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
343536Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
353536Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
363536Sgblack@eecs.umich.edu *
373536Sgblack@eecs.umich.edu * Authors: Andreas Sandberg
383536Sgblack@eecs.umich.edu */
393536Sgblack@eecs.umich.edu
403536Sgblack@eecs.umich.edu#include "dev/virtio/fs9p.hh"
415543Ssaidi@eecs.umich.edu
425543Ssaidi@eecs.umich.edu#include <fcntl.h>
433536Sgblack@eecs.umich.edu#include <netdb.h>
443536Sgblack@eecs.umich.edu#include <netinet/in.h>
453536Sgblack@eecs.umich.edu#include <sys/socket.h>
463536Sgblack@eecs.umich.edu#include <sys/types.h>
473536Sgblack@eecs.umich.edu#include <sys/un.h>
483536Sgblack@eecs.umich.edu#include <sys/wait.h>
493536Sgblack@eecs.umich.edu#include <unistd.h>
503536Sgblack@eecs.umich.edu
513536Sgblack@eecs.umich.edu#include <csignal>
523536Sgblack@eecs.umich.edu#include <fstream>
533536Sgblack@eecs.umich.edu
545543Ssaidi@eecs.umich.edu#include "base/callback.hh"
555543Ssaidi@eecs.umich.edu#include "base/output.hh"
563536Sgblack@eecs.umich.edu#include "debug/VIO9P.hh"
573536Sgblack@eecs.umich.edu#include "debug/VIO9PData.hh"
583536Sgblack@eecs.umich.edu#include "params/VirtIO9PBase.hh"
593536Sgblack@eecs.umich.edu#include "params/VirtIO9PDiod.hh"
603536Sgblack@eecs.umich.edu#include "params/VirtIO9PProxy.hh"
613536Sgblack@eecs.umich.edu#include "params/VirtIO9PSocket.hh"
623536Sgblack@eecs.umich.edu#include "sim/system.hh"
633536Sgblack@eecs.umich.edu
643536Sgblack@eecs.umich.edustruct P9MsgInfo {
653536Sgblack@eecs.umich.edu    P9MsgInfo(P9MsgType _type, std::string _name)
663536Sgblack@eecs.umich.edu        : type(_type), name(_name) {}
673536Sgblack@eecs.umich.edu
683536Sgblack@eecs.umich.edu    P9MsgType type;
693536Sgblack@eecs.umich.edu    std::string name;
703536Sgblack@eecs.umich.edu};
713536Sgblack@eecs.umich.edu
725543Ssaidi@eecs.umich.edutypedef std::map<P9MsgType, P9MsgInfo> P9MsgInfoMap;
733536Sgblack@eecs.umich.edu
743536Sgblack@eecs.umich.edu#define P9MSG(type, name)                               \
753536Sgblack@eecs.umich.edu    { (type), P9MsgInfo((type), "T" # name ) },         \
763536Sgblack@eecs.umich.edu    { (type + 1), P9MsgInfo((type + 1), "R" # name ) }
773536Sgblack@eecs.umich.edu
783536Sgblack@eecs.umich.edustatic const P9MsgInfoMap p9_msg_info {
793536Sgblack@eecs.umich.edu    P9MSG(6, LERROR),
803536Sgblack@eecs.umich.edu    P9MSG(8, STATFS),
813536Sgblack@eecs.umich.edu    P9MSG(12, LOPEN),
823536Sgblack@eecs.umich.edu    P9MSG(14, LCREATE),
833536Sgblack@eecs.umich.edu    P9MSG(16, SYMLINK),
843536Sgblack@eecs.umich.edu    P9MSG(18, MKNOD),
853536Sgblack@eecs.umich.edu    P9MSG(20, RENAME),
863536Sgblack@eecs.umich.edu    P9MSG(22, READLINK),
873536Sgblack@eecs.umich.edu    P9MSG(24, GETATTR),
883536Sgblack@eecs.umich.edu    P9MSG(26, SETATTR),
893536Sgblack@eecs.umich.edu    P9MSG(30, XATTRWALK),
903536Sgblack@eecs.umich.edu    P9MSG(32, XATTRCREATE),
913536Sgblack@eecs.umich.edu    P9MSG(40, READDIR),
925543Ssaidi@eecs.umich.edu    P9MSG(50, FSYNC),
935543Ssaidi@eecs.umich.edu    P9MSG(52, LOCK),
943536Sgblack@eecs.umich.edu    P9MSG(54, GETLOCK),
953536Sgblack@eecs.umich.edu    P9MSG(70, LINK),
963536Sgblack@eecs.umich.edu    P9MSG(72, MKDIR),
973536Sgblack@eecs.umich.edu    P9MSG(74, RENAMEAT),
983536Sgblack@eecs.umich.edu    P9MSG(76, UNLINKAT),
993536Sgblack@eecs.umich.edu    P9MSG(100, VERSION),
1003536Sgblack@eecs.umich.edu    P9MSG(102, AUTH),
1013536Sgblack@eecs.umich.edu    P9MSG(104, ATTACH),
1023536Sgblack@eecs.umich.edu    P9MSG(106, ERROR),
1033536Sgblack@eecs.umich.edu    P9MSG(108, FLUSH),
1043536Sgblack@eecs.umich.edu    P9MSG(110, WALK),
1053536Sgblack@eecs.umich.edu    P9MSG(112, OPEN),
1063536Sgblack@eecs.umich.edu    P9MSG(114, CREATE),
1073536Sgblack@eecs.umich.edu    P9MSG(116, READ),
1083536Sgblack@eecs.umich.edu    P9MSG(118, WRITE),
1093536Sgblack@eecs.umich.edu    P9MSG(120, CLUNK),
1103536Sgblack@eecs.umich.edu    P9MSG(122, REMOVE),
1113536Sgblack@eecs.umich.edu    P9MSG(124, STAT),
1123536Sgblack@eecs.umich.edu    P9MSG(126, WSTAT),
1133536Sgblack@eecs.umich.edu};
1143536Sgblack@eecs.umich.edu
1153536Sgblack@eecs.umich.edu#undef P9MSG
1163536Sgblack@eecs.umich.edu
1173536Sgblack@eecs.umich.eduVirtIO9PBase::VirtIO9PBase(Params *params)
1183536Sgblack@eecs.umich.edu    : VirtIODeviceBase(params, ID_9P,
1193536Sgblack@eecs.umich.edu                       sizeof(Config) + params->tag.size(),
1205569Snate@binkert.org                       F_MOUNT_TAG),
1213536Sgblack@eecs.umich.edu      queue(params->system->physProxy, params->queueSize, *this)
1223536Sgblack@eecs.umich.edu{
1233536Sgblack@eecs.umich.edu    config.reset((Config *)
1243961Sgblack@eecs.umich.edu                 operator new(configSize));
1253961Sgblack@eecs.umich.edu    config->len = htov_legacy(params->tag.size());
1263961Sgblack@eecs.umich.edu    memcpy(config->tag, params->tag.c_str(), params->tag.size());
1273961Sgblack@eecs.umich.edu
1283961Sgblack@eecs.umich.edu    registerQueue(queue);
1293550Sgblack@eecs.umich.edu}
1306327Sgblack@eecs.umich.edu
1313550Sgblack@eecs.umich.edu
1328229Snate@binkert.orgVirtIO9PBase::~VirtIO9PBase()
1333536Sgblack@eecs.umich.edu{
1343536Sgblack@eecs.umich.edu}
1353536Sgblack@eecs.umich.edu
1363536Sgblack@eecs.umich.eduvoid
1378229Snate@binkert.orgVirtIO9PBase::readConfig(PacketPtr pkt, Addr cfgOffset)
1383536Sgblack@eecs.umich.edu{
1393536Sgblack@eecs.umich.edu    readConfigBlob(pkt, cfgOffset, (uint8_t *)config.get());
1403536Sgblack@eecs.umich.edu}
1413536Sgblack@eecs.umich.edu
1423536Sgblack@eecs.umich.eduvoid
1433536Sgblack@eecs.umich.eduVirtIO9PBase::FSQueue::onNotifyDescriptor(VirtDescriptor *desc)
1445567Snate@binkert.org{
1453536Sgblack@eecs.umich.edu    DPRINTF(VIO9P, "Got input data descriptor (len: %i)\n", desc->size());
1465569Snate@binkert.org    DPRINTF(VIO9P, "\tPending transactions: %i\n", parent.pendingTransactions.size());
1475569Snate@binkert.org
1483536Sgblack@eecs.umich.edu    P9MsgHeader header;
1493579Sgblack@eecs.umich.edu    desc->chainRead(0, (uint8_t *)&header, sizeof(header));
1503536Sgblack@eecs.umich.edu    header = p9toh(header);
1513536Sgblack@eecs.umich.edu
1525569Snate@binkert.org    uint8_t data[header.len - sizeof(header)];
1535569Snate@binkert.org    desc->chainRead(sizeof(header), data, sizeof(data));
1545569Snate@binkert.org
1553536Sgblack@eecs.umich.edu    // Keep track of pending transactions
1563536Sgblack@eecs.umich.edu    parent.pendingTransactions[header.tag] = desc;
1573536Sgblack@eecs.umich.edu
1583961Sgblack@eecs.umich.edu    DPRINTF(VIO9P, "recvTMsg\n");
1593961Sgblack@eecs.umich.edu    parent.dumpMsg(header, data, sizeof(data));
1603961Sgblack@eecs.umich.edu
1613536Sgblack@eecs.umich.edu    // Notify device of message
1623536Sgblack@eecs.umich.edu    parent.recvTMsg(header, data, sizeof(data));
1635568Snate@binkert.org}
1645568Snate@binkert.org
1653536Sgblack@eecs.umich.eduvoid
1663536Sgblack@eecs.umich.eduVirtIO9PBase::sendRMsg(const P9MsgHeader &header, const uint8_t *data, size_t size)
1675568Snate@binkert.org{
1685568Snate@binkert.org    DPRINTF(VIO9P, "Sending RMsg\n");
1693536Sgblack@eecs.umich.edu    dumpMsg(header, data, size);
1703536Sgblack@eecs.umich.edu    DPRINTF(VIO9P, "\tPending transactions: %i\n", pendingTransactions.size());
1713536Sgblack@eecs.umich.edu    assert(header.len >= sizeof(header));
1723536Sgblack@eecs.umich.edu
1733536Sgblack@eecs.umich.edu    VirtDescriptor *main_desc(pendingTransactions[header.tag]);
1743536Sgblack@eecs.umich.edu    pendingTransactions.erase(header.tag);
1753536Sgblack@eecs.umich.edu
1763536Sgblack@eecs.umich.edu    // Find the first output descriptor
1773536Sgblack@eecs.umich.edu    VirtDescriptor *out_desc(main_desc);
1783536Sgblack@eecs.umich.edu    while (out_desc && !out_desc->isOutgoing())
1795569Snate@binkert.org        out_desc = out_desc->next();
1805569Snate@binkert.org    if (!out_desc)
1815569Snate@binkert.org        panic("sendRMsg: Framing error, no output descriptor.\n");
1825569Snate@binkert.org
1835569Snate@binkert.org    P9MsgHeader header_out(htop9(header));
1845569Snate@binkert.org    header_out.len = htop9(sizeof(P9MsgHeader) + size);
1855569Snate@binkert.org
1863536Sgblack@eecs.umich.edu    out_desc->chainWrite(0, (uint8_t *)&header_out, sizeof(header_out));
1875568Snate@binkert.org    out_desc->chainWrite(sizeof(header_out), data, size);
1883536Sgblack@eecs.umich.edu
1893536Sgblack@eecs.umich.edu    queue.produceDescriptor(main_desc, sizeof(P9MsgHeader) + size);
1905568Snate@binkert.org    kick();
1915569Snate@binkert.org}
1925569Snate@binkert.org
1933536Sgblack@eecs.umich.eduvoid
1943536Sgblack@eecs.umich.eduVirtIO9PBase::dumpMsg(const P9MsgHeader &header, const uint8_t *data, size_t size)
1953536Sgblack@eecs.umich.edu{
1963536Sgblack@eecs.umich.edu#ifndef NDEBUG
1975568Snate@binkert.org    if (!DTRACE(VIO9P))
1983536Sgblack@eecs.umich.edu        return;
1993536Sgblack@eecs.umich.edu
2003536Sgblack@eecs.umich.edu    const P9MsgInfoMap::const_iterator it_msg(p9_msg_info.find(header.type));
2013536Sgblack@eecs.umich.edu    if (it_msg != p9_msg_info.cend()) {
2023961Sgblack@eecs.umich.edu        const P9MsgInfo &info(it_msg->second);
2033536Sgblack@eecs.umich.edu        DPRINTF(VIO9P, "P9Msg[len = %i, type = %s (%i), tag = %i]\n",
2043536Sgblack@eecs.umich.edu                header.len, info.name, header.type, header.tag);
2055569Snate@binkert.org    } else {
2065569Snate@binkert.org        DPRINTF(VIO9P, "P9Msg[len = %i, type = Unknown (%i), tag = %i]\n",
2075569Snate@binkert.org                header.len, header.type, header.tag);
2085569Snate@binkert.org    }
2093536Sgblack@eecs.umich.edu    DDUMP(VIO9PData, data, size);
2103536Sgblack@eecs.umich.edu#endif
2113536Sgblack@eecs.umich.edu}
2123579Sgblack@eecs.umich.edu
2133536Sgblack@eecs.umich.edu
2147720Sgblack@eecs.umich.eduVirtIO9PProxy::VirtIO9PProxy(Params *params)
2153536Sgblack@eecs.umich.edu  : VirtIO9PBase(params), deviceUsed(false)
2163536Sgblack@eecs.umich.edu{
2175568Snate@binkert.org}
2185568Snate@binkert.org
2195568Snate@binkert.orgVirtIO9PProxy::~VirtIO9PProxy()
2203536Sgblack@eecs.umich.edu{
2213536Sgblack@eecs.umich.edu}
2225568Snate@binkert.org
2233536Sgblack@eecs.umich.edu
2243536Sgblack@eecs.umich.eduvoid
2253536Sgblack@eecs.umich.eduVirtIO9PProxy::serialize(CheckpointOut &cp) const
2263536Sgblack@eecs.umich.edu{
2273536Sgblack@eecs.umich.edu    if (deviceUsed) {
2285568Snate@binkert.org        warn("Serializing VirtIO9Base device after device has been used. It is "
2293536Sgblack@eecs.umich.edu             "likely that state will be lost, and that the device will cease "
2303536Sgblack@eecs.umich.edu             "to work!");
2313536Sgblack@eecs.umich.edu    }
2323536Sgblack@eecs.umich.edu    SERIALIZE_SCALAR(deviceUsed);
2333536Sgblack@eecs.umich.edu
2345569Snate@binkert.org    VirtIO9PBase::serialize(cp);
2355569Snate@binkert.org}
2365569Snate@binkert.org
2375569Snate@binkert.orgvoid
2383536Sgblack@eecs.umich.eduVirtIO9PProxy::unserialize(CheckpointIn &cp)
2393536Sgblack@eecs.umich.edu{
2403536Sgblack@eecs.umich.edu    UNSERIALIZE_SCALAR(deviceUsed);
2413536Sgblack@eecs.umich.edu
2425568Snate@binkert.org    if (deviceUsed) {
2435568Snate@binkert.org        warn("Unserializing VirtIO9Base device after device has been used. It is "
2445568Snate@binkert.org             "likely that state has been lost, and that the device will cease "
2453536Sgblack@eecs.umich.edu             "to work!");
2463536Sgblack@eecs.umich.edu    }
2475568Snate@binkert.org    VirtIO9PBase::unserialize(cp);
2483536Sgblack@eecs.umich.edu}
2493536Sgblack@eecs.umich.edu
2503536Sgblack@eecs.umich.edu
2513536Sgblack@eecs.umich.eduvoid
2523536Sgblack@eecs.umich.eduVirtIO9PProxy::recvTMsg(const P9MsgHeader &header,
2535568Snate@binkert.org                        const uint8_t *data, size_t size)
2543536Sgblack@eecs.umich.edu{
2553536Sgblack@eecs.umich.edu    deviceUsed = true;
2563536Sgblack@eecs.umich.edu    assert(header.len == sizeof(header) + size);
2577720Sgblack@eecs.umich.edu    // While technically not needed, we send the packet as one
2583536Sgblack@eecs.umich.edu    // contiguous segment to make some packet dissectors happy.
2593536Sgblack@eecs.umich.edu    uint8_t out[header.len];
2603536Sgblack@eecs.umich.edu    P9MsgHeader header_out(htop9(header));
2613536Sgblack@eecs.umich.edu    memcpy(out, (uint8_t *)&header_out, sizeof(header_out));
2623536Sgblack@eecs.umich.edu    memcpy(out + sizeof(header_out), data, size);
2633536Sgblack@eecs.umich.edu    writeAll(out, sizeof(header_out) + size);
2643550Sgblack@eecs.umich.edu}
2653536Sgblack@eecs.umich.edu
2663550Sgblack@eecs.umich.eduvoid
2673536Sgblack@eecs.umich.eduVirtIO9PProxy::serverDataReady()
2683536Sgblack@eecs.umich.edu{
2693550Sgblack@eecs.umich.edu    P9MsgHeader header;
2703536Sgblack@eecs.umich.edu    readAll((uint8_t *)&header, sizeof(header));
2713536Sgblack@eecs.umich.edu    header = p9toh(header);
2723536Sgblack@eecs.umich.edu
2733536Sgblack@eecs.umich.edu    const ssize_t payload_len(header.len - sizeof(header));
2743536Sgblack@eecs.umich.edu    if (payload_len < 0)
2753536Sgblack@eecs.umich.edu        panic("Payload length is negative!\n");
2767720Sgblack@eecs.umich.edu    uint8_t data[payload_len];
2777720Sgblack@eecs.umich.edu    readAll(data, payload_len);
2783536Sgblack@eecs.umich.edu
2793536Sgblack@eecs.umich.edu    sendRMsg(header, data, payload_len);
2803536Sgblack@eecs.umich.edu}
2813536Sgblack@eecs.umich.edu
2827720Sgblack@eecs.umich.edu
2837720Sgblack@eecs.umich.eduvoid
2843536Sgblack@eecs.umich.eduVirtIO9PProxy::readAll(uint8_t *data, size_t len)
2853536Sgblack@eecs.umich.edu{
2863536Sgblack@eecs.umich.edu    while (len) {
2877720Sgblack@eecs.umich.edu        ssize_t ret;
2883536Sgblack@eecs.umich.edu        while ((ret = read(data, len)) == -EAGAIN)
2893536Sgblack@eecs.umich.edu            ;
2903536Sgblack@eecs.umich.edu        if (ret < 0)
2913536Sgblack@eecs.umich.edu            panic("readAll: Read failed: %i\n", -ret);
2923550Sgblack@eecs.umich.edu
2933536Sgblack@eecs.umich.edu        len -= ret;
2947720Sgblack@eecs.umich.edu        data += ret;
2953536Sgblack@eecs.umich.edu    }
2963536Sgblack@eecs.umich.edu}
2977720Sgblack@eecs.umich.edu
2983536Sgblack@eecs.umich.eduvoid
2993536Sgblack@eecs.umich.eduVirtIO9PProxy::writeAll(const uint8_t *data, size_t len)
3003536Sgblack@eecs.umich.edu{
3013536Sgblack@eecs.umich.edu    while (len) {
3023536Sgblack@eecs.umich.edu        ssize_t ret;
3033536Sgblack@eecs.umich.edu        while ((ret = write(data, len)) == -EAGAIN)
3043536Sgblack@eecs.umich.edu            ;
3053536Sgblack@eecs.umich.edu        if (ret < 0)
3063536Sgblack@eecs.umich.edu            panic("writeAll: write failed: %i\n", -ret);
3073536Sgblack@eecs.umich.edu
3083536Sgblack@eecs.umich.edu        len -= ret;
3093536Sgblack@eecs.umich.edu        data += ret;
3103536Sgblack@eecs.umich.edu    }
3113536Sgblack@eecs.umich.edu}
3123536Sgblack@eecs.umich.edu
3133536Sgblack@eecs.umich.edu
314
315VirtIO9PDiod::VirtIO9PDiod(Params *params)
316    : VirtIO9PProxy(params),
317      fd_to_diod(-1), fd_from_diod(-1), diod_pid(-1)
318{
319    // Register an exit callback so we can kill the diod process
320    Callback* cb = new MakeCallback<VirtIO9PDiod,
321                                    &VirtIO9PDiod::terminateDiod>(this);
322    registerExitCallback(cb);
323}
324
325VirtIO9PDiod::~VirtIO9PDiod()
326{
327}
328
329void
330VirtIO9PDiod::startup()
331{
332    startDiod();
333    dataEvent.reset(new DiodDataEvent(*this, fd_from_diod, POLLIN));
334    pollQueue.schedule(dataEvent.get());
335}
336
337void
338VirtIO9PDiod::startDiod()
339{
340    const Params *p(dynamic_cast<const Params *>(params()));
341    int pipe_rfd[2];
342    int pipe_wfd[2];
343    const int DIOD_RFD = 3;
344    const int DIOD_WFD = 4;
345
346    const char *diod(p->diod.c_str());
347
348    DPRINTF(VIO9P, "Using diod at %s \n", p->diod.c_str());
349
350    if (pipe(pipe_rfd) == -1 || pipe(pipe_wfd) == -1)
351        panic("Failed to create DIOD pipes: %i\n", errno);
352
353    fd_to_diod = pipe_rfd[1];
354    fd_from_diod = pipe_wfd[0];
355
356    // Create Unix domain socket
357    int socket_id = socket(AF_UNIX, SOCK_STREAM, 0);
358    if (socket_id == -1) {
359        panic("Socket creation failed %i \n", errno);
360    }
361    // Bind the socket to a path which will not be read
362    struct sockaddr_un socket_address;
363    memset(&socket_address, 0, sizeof(struct sockaddr_un));
364    socket_address.sun_family = AF_UNIX;
365
366    const std::string socket_path = simout.resolve(p->socketPath);
367    fatal_if(!OutputDirectory::isAbsolute(socket_path), "Please make the" \
368             " output directory an absolute path, else diod will fail!\n");
369
370    // Prevent overflow in strcpy
371    fatal_if(sizeof(socket_address.sun_path) <= socket_path.length(),
372             "Incorrect length of socket path");
373    strncpy(socket_address.sun_path, socket_path.c_str(),
374            sizeof(socket_address.sun_path));
375    if (bind(socket_id, (struct sockaddr*) &socket_address,
376             sizeof(struct sockaddr_un)) == -1){
377        perror("Socket binding");
378        panic("Socket binding to %i failed - most likely the output dir" \
379              " and hence unused socket already exists \n", socket_id);
380    }
381
382    diod_pid = fork();
383    if (diod_pid == -1) {
384        panic("Fork failed: %i\n", errno);
385    } else if (diod_pid == 0) {
386        // Create the socket which will later by used by the diod process
387        close(STDIN_FILENO);
388        if (dup2(pipe_rfd[0], DIOD_RFD) == -1 ||
389            dup2(pipe_wfd[1], DIOD_WFD) == -1) {
390
391            panic("Failed to setup read/write pipes: %i\n",
392                  errno);
393        }
394
395        // Start diod
396        execlp(diod, diod,
397               "-f", // start in foreground
398               "-r", "3", // setup read FD
399               "-w", "4", // setup write FD
400               "-e", p->root.c_str(), // path to export
401               "-n", // disable security
402               "-S", // squash all users
403               "-l", socket_path.c_str(), // pass the socket
404               (char *)NULL);
405        perror("Starting DIOD");
406        panic("Failed to execute diod to %s: %i\n",socket_path, errno);
407    } else {
408        close(pipe_rfd[0]);
409        close(pipe_wfd[1]);
410        inform("Started diod with PID %u, you might need to manually kill " \
411                " diod if gem5 crashes \n", diod_pid);
412    }
413
414#undef DIOD_RFD
415#undef DIOD_WFD
416}
417
418ssize_t
419VirtIO9PDiod::read(uint8_t *data, size_t len)
420{
421    assert(fd_from_diod != -1);
422    const int ret(::read(fd_from_diod, (void *)data, len));
423    return ret < 0 ? -errno : ret;
424}
425
426ssize_t
427VirtIO9PDiod::write(const uint8_t *data, size_t len)
428{
429    assert(fd_to_diod != -1);
430    const int ret(::write(fd_to_diod, (const void *)data, len));
431    return ret < 0 ? -errno : ret;
432}
433
434void
435VirtIO9PDiod::DiodDataEvent::process(int revent)
436{
437    parent.serverDataReady();
438}
439
440void
441VirtIO9PDiod::terminateDiod()
442{
443    assert(diod_pid != -1);
444
445    DPRINTF(VIO9P, "Trying to kill diod at pid %u \n", diod_pid);
446
447    if (kill(diod_pid, SIGTERM) != 0) {
448        perror("Killing diod process");
449        warn("Failed to kill diod using SIGTERM");
450        return;
451    }
452
453    // Check if kill worked
454    for (unsigned i = 0; i < 5; i++) {
455        int wait_return = waitpid(diod_pid, NULL, WNOHANG);
456        if (wait_return == diod_pid) {
457            // Managed to kill diod
458            return;
459        } else if (wait_return == 0) {
460            // Diod is not killed so sleep and try again
461            usleep(500);
462        } else {
463            // Failed in waitpid
464            perror("Waitpid");
465            warn("Failed in waitpid");
466        }
467    }
468
469    // Try again to kill diod with sigkill
470    inform("Trying to kill diod with SIGKILL as SIGTERM failed \n");
471    if (kill(diod_pid, SIGKILL) != 0) {
472        perror("Killing diod process");
473        warn("Failed to kill diod using SIGKILL");
474    } else {
475        // Managed to kill diod
476        return;
477    }
478
479}
480VirtIO9PDiod *
481VirtIO9PDiodParams::create()
482{
483    return new VirtIO9PDiod(this);
484}
485
486
487
488
489VirtIO9PSocket::VirtIO9PSocket(Params *params)
490    : VirtIO9PProxy(params), fdSocket(-1)
491{
492}
493
494VirtIO9PSocket::~VirtIO9PSocket()
495{
496}
497
498void
499VirtIO9PSocket::startup()
500{
501    connectSocket();
502    dataEvent.reset(new SocketDataEvent(*this, fdSocket, POLLIN));
503    pollQueue.schedule(dataEvent.get());
504}
505
506void
507VirtIO9PSocket::connectSocket()
508{
509    const Params &p(dynamic_cast<const Params &>(*params()));
510
511    int ret;
512    struct addrinfo hints, *result;
513    memset(&hints, 0, sizeof(hints));
514    hints.ai_family = AF_UNSPEC;
515    hints.ai_socktype = SOCK_STREAM;
516    hints.ai_flags = 0;
517    hints.ai_protocol = 0;
518
519    if ((ret = getaddrinfo(p.server.c_str(), p.port.c_str(),
520                           &hints, &result)) != 0)
521        panic("getaddrinfo: %s\n", gai_strerror(ret));
522
523    DPRINTF(VIO9P, "Connecting to 9p server '%s'.\n", p.server);
524    for (struct addrinfo *rp = result; rp; rp = rp->ai_next) {
525        fdSocket = socket(rp->ai_family, rp->ai_socktype,
526                     rp->ai_protocol);
527        if (fdSocket == -1) {
528            continue;
529        } else if (connect(fdSocket, rp->ai_addr, rp->ai_addrlen) != -1) {
530            break;
531        } else {
532            close(fdSocket);
533            fdSocket = -1;
534        }
535    }
536
537    freeaddrinfo(result);
538
539    if (fdSocket == -1)
540        panic("Failed to connect to 9p server (%s:%s)", p.server, p.port);
541}
542
543void
544VirtIO9PSocket::socketDisconnect()
545{
546    panic("9P Socket disconnected!\n");
547}
548
549ssize_t
550VirtIO9PSocket::read(uint8_t *data, size_t len)
551{
552    assert(fdSocket != -1);
553    int ret;
554
555    ret = ::recv(fdSocket, (void *)data, len, 0);
556    if (ret == 0)
557        socketDisconnect();
558
559    return ret < 0 ? -errno : ret;
560}
561
562ssize_t
563VirtIO9PSocket::write(const uint8_t *data, size_t len)
564{
565    assert(fdSocket != -1);
566    int ret(::send(fdSocket, (const void *)data, len, 0));
567    return ret < 0 ? -errno : ret;
568}
569
570void
571VirtIO9PSocket::SocketDataEvent::process(int revent)
572{
573    parent.serverDataReady();
574}
575
576
577VirtIO9PSocket *
578VirtIO9PSocketParams::create()
579{
580    return new VirtIO9PSocket(this);
581}
582