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