fs9p.cc revision 12559
110391SAndreas.Sandberg@ARM.com/* 212076Sanouk.vanlaer@arm.com * Copyright (c) 2014-2017 ARM Limited 310391SAndreas.Sandberg@ARM.com * All rights reserved 410391SAndreas.Sandberg@ARM.com * 510391SAndreas.Sandberg@ARM.com * The license below extends only to copyright in the software and shall 610391SAndreas.Sandberg@ARM.com * not be construed as granting a license to any other intellectual 710391SAndreas.Sandberg@ARM.com * property including but not limited to intellectual property relating 810391SAndreas.Sandberg@ARM.com * to a hardware implementation of the functionality of the software 910391SAndreas.Sandberg@ARM.com * licensed hereunder. You may use the software subject to the license 1010391SAndreas.Sandberg@ARM.com * terms below provided that you ensure that this notice is replicated 1110391SAndreas.Sandberg@ARM.com * unmodified and in its entirety in all distributions of the software, 1210391SAndreas.Sandberg@ARM.com * modified or unmodified, in source code or in binary form. 1310391SAndreas.Sandberg@ARM.com * 1410391SAndreas.Sandberg@ARM.com * Redistribution and use in source and binary forms, with or without 1510391SAndreas.Sandberg@ARM.com * modification, are permitted provided that the following conditions are 1610391SAndreas.Sandberg@ARM.com * met: redistributions of source code must retain the above copyright 1710391SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer; 1810391SAndreas.Sandberg@ARM.com * redistributions in binary form must reproduce the above copyright 1910391SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer in the 2010391SAndreas.Sandberg@ARM.com * documentation and/or other materials provided with the distribution; 2110391SAndreas.Sandberg@ARM.com * neither the name of the copyright holders nor the names of its 2210391SAndreas.Sandberg@ARM.com * contributors may be used to endorse or promote products derived from 2310391SAndreas.Sandberg@ARM.com * this software without specific prior written permission. 2410391SAndreas.Sandberg@ARM.com * 2510391SAndreas.Sandberg@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2610391SAndreas.Sandberg@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2710391SAndreas.Sandberg@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2810391SAndreas.Sandberg@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2910391SAndreas.Sandberg@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3010391SAndreas.Sandberg@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3110391SAndreas.Sandberg@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3210391SAndreas.Sandberg@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3310391SAndreas.Sandberg@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3410391SAndreas.Sandberg@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3510391SAndreas.Sandberg@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3610391SAndreas.Sandberg@ARM.com * 3710391SAndreas.Sandberg@ARM.com * Authors: Andreas Sandberg 3810391SAndreas.Sandberg@ARM.com */ 3910391SAndreas.Sandberg@ARM.com 4011793Sbrandon.potter@amd.com#include "dev/virtio/fs9p.hh" 4111793Sbrandon.potter@amd.com 4211793Sbrandon.potter@amd.com#include <fcntl.h> 4311793Sbrandon.potter@amd.com#include <netdb.h> 4410391SAndreas.Sandberg@ARM.com#include <netinet/in.h> 4510391SAndreas.Sandberg@ARM.com#include <sys/socket.h> 4610391SAndreas.Sandberg@ARM.com#include <sys/types.h> 4712076Sanouk.vanlaer@arm.com#include <sys/un.h> 4812187Sanouk.vanlaer@arm.com#include <sys/wait.h> 4910391SAndreas.Sandberg@ARM.com#include <unistd.h> 5010391SAndreas.Sandberg@ARM.com 5112187Sanouk.vanlaer@arm.com#include <csignal> 5212076Sanouk.vanlaer@arm.com#include <fstream> 5312076Sanouk.vanlaer@arm.com 5412187Sanouk.vanlaer@arm.com#include "base/callback.hh" 5512076Sanouk.vanlaer@arm.com#include "base/output.hh" 5610391SAndreas.Sandberg@ARM.com#include "debug/VIO9P.hh" 5710391SAndreas.Sandberg@ARM.com#include "debug/VIO9PData.hh" 5810391SAndreas.Sandberg@ARM.com#include "params/VirtIO9PBase.hh" 5910391SAndreas.Sandberg@ARM.com#include "params/VirtIO9PDiod.hh" 6010391SAndreas.Sandberg@ARM.com#include "params/VirtIO9PProxy.hh" 6110391SAndreas.Sandberg@ARM.com#include "params/VirtIO9PSocket.hh" 6210391SAndreas.Sandberg@ARM.com#include "sim/system.hh" 6310391SAndreas.Sandberg@ARM.com 6410391SAndreas.Sandberg@ARM.comstruct P9MsgInfo { 6510391SAndreas.Sandberg@ARM.com P9MsgInfo(P9MsgType _type, std::string _name) 6610391SAndreas.Sandberg@ARM.com : type(_type), name(_name) {} 6710391SAndreas.Sandberg@ARM.com 6810391SAndreas.Sandberg@ARM.com P9MsgType type; 6910391SAndreas.Sandberg@ARM.com std::string name; 7010391SAndreas.Sandberg@ARM.com}; 7110391SAndreas.Sandberg@ARM.com 7210391SAndreas.Sandberg@ARM.comtypedef std::map<P9MsgType, P9MsgInfo> P9MsgInfoMap; 7310391SAndreas.Sandberg@ARM.com 7410391SAndreas.Sandberg@ARM.com#define P9MSG(type, name) \ 7510391SAndreas.Sandberg@ARM.com { (type), P9MsgInfo((type), "T" # name ) }, \ 7610391SAndreas.Sandberg@ARM.com { (type + 1), P9MsgInfo((type + 1), "R" # name ) } 7710391SAndreas.Sandberg@ARM.com 7810391SAndreas.Sandberg@ARM.comstatic const P9MsgInfoMap p9_msg_info { 7910391SAndreas.Sandberg@ARM.com P9MSG(6, LERROR), 8010391SAndreas.Sandberg@ARM.com P9MSG(8, STATFS), 8110391SAndreas.Sandberg@ARM.com P9MSG(12, LOPEN), 8210391SAndreas.Sandberg@ARM.com P9MSG(14, LCREATE), 8310391SAndreas.Sandberg@ARM.com P9MSG(16, SYMLINK), 8410391SAndreas.Sandberg@ARM.com P9MSG(18, MKNOD), 8510391SAndreas.Sandberg@ARM.com P9MSG(20, RENAME), 8610391SAndreas.Sandberg@ARM.com P9MSG(22, READLINK), 8710391SAndreas.Sandberg@ARM.com P9MSG(24, GETATTR), 8810391SAndreas.Sandberg@ARM.com P9MSG(26, SETATTR), 8910391SAndreas.Sandberg@ARM.com P9MSG(30, XATTRWALK), 9010391SAndreas.Sandberg@ARM.com P9MSG(32, XATTRCREATE), 9110391SAndreas.Sandberg@ARM.com P9MSG(40, READDIR), 9210391SAndreas.Sandberg@ARM.com P9MSG(50, FSYNC), 9310391SAndreas.Sandberg@ARM.com P9MSG(52, LOCK), 9410391SAndreas.Sandberg@ARM.com P9MSG(54, GETLOCK), 9510391SAndreas.Sandberg@ARM.com P9MSG(70, LINK), 9610391SAndreas.Sandberg@ARM.com P9MSG(72, MKDIR), 9710391SAndreas.Sandberg@ARM.com P9MSG(74, RENAMEAT), 9810391SAndreas.Sandberg@ARM.com P9MSG(76, UNLINKAT), 9910391SAndreas.Sandberg@ARM.com P9MSG(100, VERSION), 10010391SAndreas.Sandberg@ARM.com P9MSG(102, AUTH), 10110391SAndreas.Sandberg@ARM.com P9MSG(104, ATTACH), 10210391SAndreas.Sandberg@ARM.com P9MSG(106, ERROR), 10310391SAndreas.Sandberg@ARM.com P9MSG(108, FLUSH), 10410391SAndreas.Sandberg@ARM.com P9MSG(110, WALK), 10510391SAndreas.Sandberg@ARM.com P9MSG(112, OPEN), 10610391SAndreas.Sandberg@ARM.com P9MSG(114, CREATE), 10710391SAndreas.Sandberg@ARM.com P9MSG(116, READ), 10810391SAndreas.Sandberg@ARM.com P9MSG(118, WRITE), 10910391SAndreas.Sandberg@ARM.com P9MSG(120, CLUNK), 11010391SAndreas.Sandberg@ARM.com P9MSG(122, REMOVE), 11110391SAndreas.Sandberg@ARM.com P9MSG(124, STAT), 11210391SAndreas.Sandberg@ARM.com P9MSG(126, WSTAT), 11310391SAndreas.Sandberg@ARM.com}; 11410391SAndreas.Sandberg@ARM.com 11510391SAndreas.Sandberg@ARM.com#undef P9MSG 11610391SAndreas.Sandberg@ARM.com 11710391SAndreas.Sandberg@ARM.comVirtIO9PBase::VirtIO9PBase(Params *params) 11810391SAndreas.Sandberg@ARM.com : VirtIODeviceBase(params, ID_9P, 11910391SAndreas.Sandberg@ARM.com sizeof(Config) + params->tag.size(), 12010391SAndreas.Sandberg@ARM.com F_MOUNT_TAG), 12110391SAndreas.Sandberg@ARM.com queue(params->system->physProxy, params->queueSize, *this) 12210391SAndreas.Sandberg@ARM.com{ 12310391SAndreas.Sandberg@ARM.com config.reset((Config *) 12410391SAndreas.Sandberg@ARM.com operator new(configSize)); 12510391SAndreas.Sandberg@ARM.com config->len = htov_legacy(params->tag.size()); 12610391SAndreas.Sandberg@ARM.com memcpy(config->tag, params->tag.c_str(), params->tag.size()); 12710391SAndreas.Sandberg@ARM.com 12810391SAndreas.Sandberg@ARM.com registerQueue(queue); 12910391SAndreas.Sandberg@ARM.com} 13010391SAndreas.Sandberg@ARM.com 13110391SAndreas.Sandberg@ARM.com 13210391SAndreas.Sandberg@ARM.comVirtIO9PBase::~VirtIO9PBase() 13310391SAndreas.Sandberg@ARM.com{ 13410391SAndreas.Sandberg@ARM.com} 13510391SAndreas.Sandberg@ARM.com 13610391SAndreas.Sandberg@ARM.comvoid 13710391SAndreas.Sandberg@ARM.comVirtIO9PBase::readConfig(PacketPtr pkt, Addr cfgOffset) 13810391SAndreas.Sandberg@ARM.com{ 13910391SAndreas.Sandberg@ARM.com readConfigBlob(pkt, cfgOffset, (uint8_t *)config.get()); 14010391SAndreas.Sandberg@ARM.com} 14110391SAndreas.Sandberg@ARM.com 14210391SAndreas.Sandberg@ARM.comvoid 14310391SAndreas.Sandberg@ARM.comVirtIO9PBase::FSQueue::onNotifyDescriptor(VirtDescriptor *desc) 14410391SAndreas.Sandberg@ARM.com{ 14510391SAndreas.Sandberg@ARM.com DPRINTF(VIO9P, "Got input data descriptor (len: %i)\n", desc->size()); 14610391SAndreas.Sandberg@ARM.com DPRINTF(VIO9P, "\tPending transactions: %i\n", parent.pendingTransactions.size()); 14710391SAndreas.Sandberg@ARM.com 14810391SAndreas.Sandberg@ARM.com P9MsgHeader header; 14910391SAndreas.Sandberg@ARM.com desc->chainRead(0, (uint8_t *)&header, sizeof(header)); 15010391SAndreas.Sandberg@ARM.com header = p9toh(header); 15110391SAndreas.Sandberg@ARM.com 15210391SAndreas.Sandberg@ARM.com uint8_t data[header.len - sizeof(header)]; 15310391SAndreas.Sandberg@ARM.com desc->chainRead(sizeof(header), data, sizeof(data)); 15410391SAndreas.Sandberg@ARM.com 15510391SAndreas.Sandberg@ARM.com // Keep track of pending transactions 15610391SAndreas.Sandberg@ARM.com parent.pendingTransactions[header.tag] = desc; 15710391SAndreas.Sandberg@ARM.com 15810391SAndreas.Sandberg@ARM.com DPRINTF(VIO9P, "recvTMsg\n"); 15910391SAndreas.Sandberg@ARM.com parent.dumpMsg(header, data, sizeof(data)); 16010391SAndreas.Sandberg@ARM.com 16110391SAndreas.Sandberg@ARM.com // Notify device of message 16210391SAndreas.Sandberg@ARM.com parent.recvTMsg(header, data, sizeof(data)); 16310391SAndreas.Sandberg@ARM.com} 16410391SAndreas.Sandberg@ARM.com 16510391SAndreas.Sandberg@ARM.comvoid 16610391SAndreas.Sandberg@ARM.comVirtIO9PBase::sendRMsg(const P9MsgHeader &header, const uint8_t *data, size_t size) 16710391SAndreas.Sandberg@ARM.com{ 16810391SAndreas.Sandberg@ARM.com DPRINTF(VIO9P, "Sending RMsg\n"); 16910391SAndreas.Sandberg@ARM.com dumpMsg(header, data, size); 17010391SAndreas.Sandberg@ARM.com DPRINTF(VIO9P, "\tPending transactions: %i\n", pendingTransactions.size()); 17110391SAndreas.Sandberg@ARM.com assert(header.len >= sizeof(header)); 17210391SAndreas.Sandberg@ARM.com 17310391SAndreas.Sandberg@ARM.com VirtDescriptor *main_desc(pendingTransactions[header.tag]); 17410391SAndreas.Sandberg@ARM.com pendingTransactions.erase(header.tag); 17510391SAndreas.Sandberg@ARM.com 17610391SAndreas.Sandberg@ARM.com // Find the first output descriptor 17710391SAndreas.Sandberg@ARM.com VirtDescriptor *out_desc(main_desc); 17810391SAndreas.Sandberg@ARM.com while (out_desc && !out_desc->isOutgoing()) 17910391SAndreas.Sandberg@ARM.com out_desc = out_desc->next(); 18010391SAndreas.Sandberg@ARM.com if (!out_desc) 18110391SAndreas.Sandberg@ARM.com panic("sendRMsg: Framing error, no output descriptor.\n"); 18210391SAndreas.Sandberg@ARM.com 18310391SAndreas.Sandberg@ARM.com P9MsgHeader header_out(htop9(header)); 18410391SAndreas.Sandberg@ARM.com header_out.len = htop9(sizeof(P9MsgHeader) + size); 18510391SAndreas.Sandberg@ARM.com 18610391SAndreas.Sandberg@ARM.com out_desc->chainWrite(0, (uint8_t *)&header_out, sizeof(header_out)); 18710391SAndreas.Sandberg@ARM.com out_desc->chainWrite(sizeof(header_out), data, size); 18810391SAndreas.Sandberg@ARM.com 18910391SAndreas.Sandberg@ARM.com queue.produceDescriptor(main_desc, sizeof(P9MsgHeader) + size); 19010391SAndreas.Sandberg@ARM.com kick(); 19110391SAndreas.Sandberg@ARM.com} 19210391SAndreas.Sandberg@ARM.com 19310391SAndreas.Sandberg@ARM.comvoid 19410391SAndreas.Sandberg@ARM.comVirtIO9PBase::dumpMsg(const P9MsgHeader &header, const uint8_t *data, size_t size) 19510391SAndreas.Sandberg@ARM.com{ 19610391SAndreas.Sandberg@ARM.com#ifndef NDEBUG 19710391SAndreas.Sandberg@ARM.com if (!DTRACE(VIO9P)) 19810391SAndreas.Sandberg@ARM.com return; 19910391SAndreas.Sandberg@ARM.com 20010391SAndreas.Sandberg@ARM.com const P9MsgInfoMap::const_iterator it_msg(p9_msg_info.find(header.type)); 20110391SAndreas.Sandberg@ARM.com if (it_msg != p9_msg_info.cend()) { 20210391SAndreas.Sandberg@ARM.com const P9MsgInfo &info(it_msg->second); 20310391SAndreas.Sandberg@ARM.com DPRINTF(VIO9P, "P9Msg[len = %i, type = %s (%i), tag = %i]\n", 20410391SAndreas.Sandberg@ARM.com header.len, info.name, header.type, header.tag); 20510391SAndreas.Sandberg@ARM.com } else { 20610391SAndreas.Sandberg@ARM.com DPRINTF(VIO9P, "P9Msg[len = %i, type = Unknown (%i), tag = %i]\n", 20710391SAndreas.Sandberg@ARM.com header.len, header.type, header.tag); 20810391SAndreas.Sandberg@ARM.com } 20910391SAndreas.Sandberg@ARM.com DDUMP(VIO9PData, data, size); 21010391SAndreas.Sandberg@ARM.com#endif 21110391SAndreas.Sandberg@ARM.com} 21210391SAndreas.Sandberg@ARM.com 21310391SAndreas.Sandberg@ARM.com 21410391SAndreas.Sandberg@ARM.comVirtIO9PProxy::VirtIO9PProxy(Params *params) 21511204Ssascha.bischoff@ARM.com : VirtIO9PBase(params), deviceUsed(false) 21610391SAndreas.Sandberg@ARM.com{ 21710391SAndreas.Sandberg@ARM.com} 21810391SAndreas.Sandberg@ARM.com 21910391SAndreas.Sandberg@ARM.comVirtIO9PProxy::~VirtIO9PProxy() 22010391SAndreas.Sandberg@ARM.com{ 22110391SAndreas.Sandberg@ARM.com} 22210391SAndreas.Sandberg@ARM.com 22310391SAndreas.Sandberg@ARM.com 22410391SAndreas.Sandberg@ARM.comvoid 22511204Ssascha.bischoff@ARM.comVirtIO9PProxy::serialize(CheckpointOut &cp) const 22610391SAndreas.Sandberg@ARM.com{ 22711204Ssascha.bischoff@ARM.com if (deviceUsed) { 22811204Ssascha.bischoff@ARM.com warn("Serializing VirtIO9Base device after device has been used. It is " 22911204Ssascha.bischoff@ARM.com "likely that state will be lost, and that the device will cease " 23011204Ssascha.bischoff@ARM.com "to work!"); 23111204Ssascha.bischoff@ARM.com } 23211204Ssascha.bischoff@ARM.com SERIALIZE_SCALAR(deviceUsed); 23311204Ssascha.bischoff@ARM.com 23411204Ssascha.bischoff@ARM.com VirtIO9PBase::serialize(cp); 23510391SAndreas.Sandberg@ARM.com} 23610391SAndreas.Sandberg@ARM.com 23710391SAndreas.Sandberg@ARM.comvoid 23810905Sandreas.sandberg@arm.comVirtIO9PProxy::unserialize(CheckpointIn &cp) 23910391SAndreas.Sandberg@ARM.com{ 24011204Ssascha.bischoff@ARM.com UNSERIALIZE_SCALAR(deviceUsed); 24111204Ssascha.bischoff@ARM.com 24211204Ssascha.bischoff@ARM.com if (deviceUsed) { 24311204Ssascha.bischoff@ARM.com warn("Unserializing VirtIO9Base device after device has been used. It is " 24411204Ssascha.bischoff@ARM.com "likely that state has been lost, and that the device will cease " 24511204Ssascha.bischoff@ARM.com "to work!"); 24611204Ssascha.bischoff@ARM.com } 24711204Ssascha.bischoff@ARM.com VirtIO9PBase::unserialize(cp); 24810391SAndreas.Sandberg@ARM.com} 24910391SAndreas.Sandberg@ARM.com 25010391SAndreas.Sandberg@ARM.com 25110391SAndreas.Sandberg@ARM.comvoid 25210391SAndreas.Sandberg@ARM.comVirtIO9PProxy::recvTMsg(const P9MsgHeader &header, 25310391SAndreas.Sandberg@ARM.com const uint8_t *data, size_t size) 25410391SAndreas.Sandberg@ARM.com{ 25511204Ssascha.bischoff@ARM.com deviceUsed = true; 25610391SAndreas.Sandberg@ARM.com assert(header.len == sizeof(header) + size); 25710391SAndreas.Sandberg@ARM.com // While technically not needed, we send the packet as one 25810391SAndreas.Sandberg@ARM.com // contiguous segment to make some packet dissectors happy. 25910391SAndreas.Sandberg@ARM.com uint8_t out[header.len]; 26010391SAndreas.Sandberg@ARM.com P9MsgHeader header_out(htop9(header)); 26110391SAndreas.Sandberg@ARM.com memcpy(out, (uint8_t *)&header_out, sizeof(header_out)); 26210391SAndreas.Sandberg@ARM.com memcpy(out + sizeof(header_out), data, size); 26310391SAndreas.Sandberg@ARM.com writeAll(out, sizeof(header_out) + size); 26410391SAndreas.Sandberg@ARM.com} 26510391SAndreas.Sandberg@ARM.com 26610391SAndreas.Sandberg@ARM.comvoid 26710391SAndreas.Sandberg@ARM.comVirtIO9PProxy::serverDataReady() 26810391SAndreas.Sandberg@ARM.com{ 26910391SAndreas.Sandberg@ARM.com P9MsgHeader header; 27010391SAndreas.Sandberg@ARM.com readAll((uint8_t *)&header, sizeof(header)); 27110391SAndreas.Sandberg@ARM.com header = p9toh(header); 27210391SAndreas.Sandberg@ARM.com 27310391SAndreas.Sandberg@ARM.com const ssize_t payload_len(header.len - sizeof(header)); 27410391SAndreas.Sandberg@ARM.com if (payload_len < 0) 27510391SAndreas.Sandberg@ARM.com panic("Payload length is negative!\n"); 27610391SAndreas.Sandberg@ARM.com uint8_t data[payload_len]; 27710391SAndreas.Sandberg@ARM.com readAll(data, payload_len); 27810391SAndreas.Sandberg@ARM.com 27910391SAndreas.Sandberg@ARM.com sendRMsg(header, data, payload_len); 28010391SAndreas.Sandberg@ARM.com} 28110391SAndreas.Sandberg@ARM.com 28210391SAndreas.Sandberg@ARM.com 28310391SAndreas.Sandberg@ARM.comvoid 28410391SAndreas.Sandberg@ARM.comVirtIO9PProxy::readAll(uint8_t *data, size_t len) 28510391SAndreas.Sandberg@ARM.com{ 28610391SAndreas.Sandberg@ARM.com while (len) { 28710391SAndreas.Sandberg@ARM.com ssize_t ret; 28810391SAndreas.Sandberg@ARM.com while ((ret = read(data, len)) == -EAGAIN) 28910391SAndreas.Sandberg@ARM.com ; 29010391SAndreas.Sandberg@ARM.com if (ret < 0) 29110391SAndreas.Sandberg@ARM.com panic("readAll: Read failed: %i\n", -ret); 29210391SAndreas.Sandberg@ARM.com 29310391SAndreas.Sandberg@ARM.com len -= ret; 29410391SAndreas.Sandberg@ARM.com data += ret; 29510391SAndreas.Sandberg@ARM.com } 29610391SAndreas.Sandberg@ARM.com} 29710391SAndreas.Sandberg@ARM.com 29810391SAndreas.Sandberg@ARM.comvoid 29910391SAndreas.Sandberg@ARM.comVirtIO9PProxy::writeAll(const uint8_t *data, size_t len) 30010391SAndreas.Sandberg@ARM.com{ 30110391SAndreas.Sandberg@ARM.com while (len) { 30210391SAndreas.Sandberg@ARM.com ssize_t ret; 30310391SAndreas.Sandberg@ARM.com while ((ret = write(data, len)) == -EAGAIN) 30410391SAndreas.Sandberg@ARM.com ; 30510391SAndreas.Sandberg@ARM.com if (ret < 0) 30610391SAndreas.Sandberg@ARM.com panic("writeAll: write failed: %i\n", -ret); 30710391SAndreas.Sandberg@ARM.com 30810391SAndreas.Sandberg@ARM.com len -= ret; 30910391SAndreas.Sandberg@ARM.com data += ret; 31010391SAndreas.Sandberg@ARM.com } 31110391SAndreas.Sandberg@ARM.com} 31210391SAndreas.Sandberg@ARM.com 31310391SAndreas.Sandberg@ARM.com 31410391SAndreas.Sandberg@ARM.com 31510391SAndreas.Sandberg@ARM.comVirtIO9PDiod::VirtIO9PDiod(Params *params) 31610391SAndreas.Sandberg@ARM.com : VirtIO9PProxy(params), 31710559Sandreas.hansson@arm.com fd_to_diod(-1), fd_from_diod(-1), diod_pid(-1) 31810391SAndreas.Sandberg@ARM.com{ 31912187Sanouk.vanlaer@arm.com // Register an exit callback so we can kill the diod process 32012187Sanouk.vanlaer@arm.com Callback* cb = new MakeCallback<VirtIO9PDiod, 32112187Sanouk.vanlaer@arm.com &VirtIO9PDiod::terminateDiod>(this); 32212187Sanouk.vanlaer@arm.com registerExitCallback(cb); 32310391SAndreas.Sandberg@ARM.com} 32410391SAndreas.Sandberg@ARM.com 32510391SAndreas.Sandberg@ARM.comVirtIO9PDiod::~VirtIO9PDiod() 32610391SAndreas.Sandberg@ARM.com{ 32710391SAndreas.Sandberg@ARM.com} 32810391SAndreas.Sandberg@ARM.com 32910391SAndreas.Sandberg@ARM.comvoid 33010391SAndreas.Sandberg@ARM.comVirtIO9PDiod::startup() 33110391SAndreas.Sandberg@ARM.com{ 33210391SAndreas.Sandberg@ARM.com startDiod(); 33310391SAndreas.Sandberg@ARM.com dataEvent.reset(new DiodDataEvent(*this, fd_from_diod, POLLIN)); 33410391SAndreas.Sandberg@ARM.com pollQueue.schedule(dataEvent.get()); 33510391SAndreas.Sandberg@ARM.com} 33610391SAndreas.Sandberg@ARM.com 33710391SAndreas.Sandberg@ARM.comvoid 33810391SAndreas.Sandberg@ARM.comVirtIO9PDiod::startDiod() 33910391SAndreas.Sandberg@ARM.com{ 34010391SAndreas.Sandberg@ARM.com const Params *p(dynamic_cast<const Params *>(params())); 34110391SAndreas.Sandberg@ARM.com int pipe_rfd[2]; 34210391SAndreas.Sandberg@ARM.com int pipe_wfd[2]; 34310391SAndreas.Sandberg@ARM.com const int DIOD_RFD = 3; 34410391SAndreas.Sandberg@ARM.com const int DIOD_WFD = 4; 34510391SAndreas.Sandberg@ARM.com 34610391SAndreas.Sandberg@ARM.com const char *diod(p->diod.c_str()); 34710391SAndreas.Sandberg@ARM.com 34812076Sanouk.vanlaer@arm.com DPRINTF(VIO9P, "Using diod at %s \n", p->diod.c_str()); 34912076Sanouk.vanlaer@arm.com 35010391SAndreas.Sandberg@ARM.com if (pipe(pipe_rfd) == -1 || pipe(pipe_wfd) == -1) 35110391SAndreas.Sandberg@ARM.com panic("Failed to create DIOD pipes: %i\n", errno); 35210391SAndreas.Sandberg@ARM.com 35310391SAndreas.Sandberg@ARM.com fd_to_diod = pipe_rfd[1]; 35410391SAndreas.Sandberg@ARM.com fd_from_diod = pipe_wfd[0]; 35510391SAndreas.Sandberg@ARM.com 35612187Sanouk.vanlaer@arm.com // Create Unix domain socket 35712187Sanouk.vanlaer@arm.com int socket_id = socket(AF_UNIX, SOCK_STREAM, 0); 35812187Sanouk.vanlaer@arm.com if (socket_id == -1) { 35912187Sanouk.vanlaer@arm.com panic("Socket creation failed %i \n", errno); 36012187Sanouk.vanlaer@arm.com } 36112187Sanouk.vanlaer@arm.com // Bind the socket to a path which will not be read 36212187Sanouk.vanlaer@arm.com struct sockaddr_un socket_address; 36312187Sanouk.vanlaer@arm.com memset(&socket_address, 0, sizeof(struct sockaddr_un)); 36412187Sanouk.vanlaer@arm.com socket_address.sun_family = AF_UNIX; 36512187Sanouk.vanlaer@arm.com 36612187Sanouk.vanlaer@arm.com const std::string socket_path = simout.resolve(p->socketPath); 36712187Sanouk.vanlaer@arm.com fatal_if(!OutputDirectory::isAbsolute(socket_path), "Please make the" \ 36812187Sanouk.vanlaer@arm.com " output directory an absolute path, else diod will fail!\n"); 36912187Sanouk.vanlaer@arm.com 37012187Sanouk.vanlaer@arm.com // Prevent overflow in strcpy 37112187Sanouk.vanlaer@arm.com fatal_if(sizeof(socket_address.sun_path) <= socket_path.length(), 37212187Sanouk.vanlaer@arm.com "Incorrect length of socket path"); 37312187Sanouk.vanlaer@arm.com strncpy(socket_address.sun_path, socket_path.c_str(), 37412559Ssiddhesh.poyarekar@gmail.com sizeof(socket_address.sun_path) - 1); 37512187Sanouk.vanlaer@arm.com if (bind(socket_id, (struct sockaddr*) &socket_address, 37612187Sanouk.vanlaer@arm.com sizeof(struct sockaddr_un)) == -1){ 37712187Sanouk.vanlaer@arm.com perror("Socket binding"); 37812187Sanouk.vanlaer@arm.com panic("Socket binding to %i failed - most likely the output dir" \ 37912187Sanouk.vanlaer@arm.com " and hence unused socket already exists \n", socket_id); 38012187Sanouk.vanlaer@arm.com } 38112187Sanouk.vanlaer@arm.com 38210391SAndreas.Sandberg@ARM.com diod_pid = fork(); 38310391SAndreas.Sandberg@ARM.com if (diod_pid == -1) { 38410391SAndreas.Sandberg@ARM.com panic("Fork failed: %i\n", errno); 38510391SAndreas.Sandberg@ARM.com } else if (diod_pid == 0) { 38612187Sanouk.vanlaer@arm.com // Create the socket which will later by used by the diod process 38710391SAndreas.Sandberg@ARM.com close(STDIN_FILENO); 38810391SAndreas.Sandberg@ARM.com if (dup2(pipe_rfd[0], DIOD_RFD) == -1 || 38910391SAndreas.Sandberg@ARM.com dup2(pipe_wfd[1], DIOD_WFD) == -1) { 39010391SAndreas.Sandberg@ARM.com 39110391SAndreas.Sandberg@ARM.com panic("Failed to setup read/write pipes: %i\n", 39210391SAndreas.Sandberg@ARM.com errno); 39310391SAndreas.Sandberg@ARM.com } 39410391SAndreas.Sandberg@ARM.com 39512187Sanouk.vanlaer@arm.com // Start diod 39610391SAndreas.Sandberg@ARM.com execlp(diod, diod, 39710391SAndreas.Sandberg@ARM.com "-f", // start in foreground 39810391SAndreas.Sandberg@ARM.com "-r", "3", // setup read FD 39910391SAndreas.Sandberg@ARM.com "-w", "4", // setup write FD 40010391SAndreas.Sandberg@ARM.com "-e", p->root.c_str(), // path to export 40110391SAndreas.Sandberg@ARM.com "-n", // disable security 40210391SAndreas.Sandberg@ARM.com "-S", // squash all users 40312076Sanouk.vanlaer@arm.com "-l", socket_path.c_str(), // pass the socket 40410391SAndreas.Sandberg@ARM.com (char *)NULL); 40512076Sanouk.vanlaer@arm.com perror("Starting DIOD"); 40612076Sanouk.vanlaer@arm.com panic("Failed to execute diod to %s: %i\n",socket_path, errno); 40710391SAndreas.Sandberg@ARM.com } else { 40810391SAndreas.Sandberg@ARM.com close(pipe_rfd[0]); 40910391SAndreas.Sandberg@ARM.com close(pipe_wfd[1]); 41012187Sanouk.vanlaer@arm.com inform("Started diod with PID %u, you might need to manually kill " \ 41112187Sanouk.vanlaer@arm.com " diod if gem5 crashes \n", diod_pid); 41210391SAndreas.Sandberg@ARM.com } 41310391SAndreas.Sandberg@ARM.com 41410391SAndreas.Sandberg@ARM.com#undef DIOD_RFD 41510391SAndreas.Sandberg@ARM.com#undef DIOD_WFD 41610391SAndreas.Sandberg@ARM.com} 41710391SAndreas.Sandberg@ARM.com 41810391SAndreas.Sandberg@ARM.comssize_t 41910391SAndreas.Sandberg@ARM.comVirtIO9PDiod::read(uint8_t *data, size_t len) 42010391SAndreas.Sandberg@ARM.com{ 42110391SAndreas.Sandberg@ARM.com assert(fd_from_diod != -1); 42210391SAndreas.Sandberg@ARM.com const int ret(::read(fd_from_diod, (void *)data, len)); 42310391SAndreas.Sandberg@ARM.com return ret < 0 ? -errno : ret; 42410391SAndreas.Sandberg@ARM.com} 42510391SAndreas.Sandberg@ARM.com 42610391SAndreas.Sandberg@ARM.comssize_t 42710391SAndreas.Sandberg@ARM.comVirtIO9PDiod::write(const uint8_t *data, size_t len) 42810391SAndreas.Sandberg@ARM.com{ 42910391SAndreas.Sandberg@ARM.com assert(fd_to_diod != -1); 43010391SAndreas.Sandberg@ARM.com const int ret(::write(fd_to_diod, (const void *)data, len)); 43110391SAndreas.Sandberg@ARM.com return ret < 0 ? -errno : ret; 43210391SAndreas.Sandberg@ARM.com} 43310391SAndreas.Sandberg@ARM.com 43410391SAndreas.Sandberg@ARM.comvoid 43510391SAndreas.Sandberg@ARM.comVirtIO9PDiod::DiodDataEvent::process(int revent) 43610391SAndreas.Sandberg@ARM.com{ 43710391SAndreas.Sandberg@ARM.com parent.serverDataReady(); 43810391SAndreas.Sandberg@ARM.com} 43910391SAndreas.Sandberg@ARM.com 44012187Sanouk.vanlaer@arm.comvoid 44112187Sanouk.vanlaer@arm.comVirtIO9PDiod::terminateDiod() 44212187Sanouk.vanlaer@arm.com{ 44312187Sanouk.vanlaer@arm.com assert(diod_pid != -1); 44412187Sanouk.vanlaer@arm.com 44512187Sanouk.vanlaer@arm.com DPRINTF(VIO9P, "Trying to kill diod at pid %u \n", diod_pid); 44612187Sanouk.vanlaer@arm.com 44712187Sanouk.vanlaer@arm.com if (kill(diod_pid, SIGTERM) != 0) { 44812187Sanouk.vanlaer@arm.com perror("Killing diod process"); 44912187Sanouk.vanlaer@arm.com warn("Failed to kill diod using SIGTERM"); 45012187Sanouk.vanlaer@arm.com return; 45112187Sanouk.vanlaer@arm.com } 45212187Sanouk.vanlaer@arm.com 45312187Sanouk.vanlaer@arm.com // Check if kill worked 45412187Sanouk.vanlaer@arm.com for (unsigned i = 0; i < 5; i++) { 45512187Sanouk.vanlaer@arm.com int wait_return = waitpid(diod_pid, NULL, WNOHANG); 45612187Sanouk.vanlaer@arm.com if (wait_return == diod_pid) { 45712187Sanouk.vanlaer@arm.com // Managed to kill diod 45812187Sanouk.vanlaer@arm.com return; 45912187Sanouk.vanlaer@arm.com } else if (wait_return == 0) { 46012187Sanouk.vanlaer@arm.com // Diod is not killed so sleep and try again 46112187Sanouk.vanlaer@arm.com usleep(500); 46212187Sanouk.vanlaer@arm.com } else { 46312187Sanouk.vanlaer@arm.com // Failed in waitpid 46412187Sanouk.vanlaer@arm.com perror("Waitpid"); 46512187Sanouk.vanlaer@arm.com warn("Failed in waitpid"); 46612187Sanouk.vanlaer@arm.com } 46712187Sanouk.vanlaer@arm.com } 46812187Sanouk.vanlaer@arm.com 46912187Sanouk.vanlaer@arm.com // Try again to kill diod with sigkill 47012187Sanouk.vanlaer@arm.com inform("Trying to kill diod with SIGKILL as SIGTERM failed \n"); 47112187Sanouk.vanlaer@arm.com if (kill(diod_pid, SIGKILL) != 0) { 47212187Sanouk.vanlaer@arm.com perror("Killing diod process"); 47312187Sanouk.vanlaer@arm.com warn("Failed to kill diod using SIGKILL"); 47412187Sanouk.vanlaer@arm.com } else { 47512187Sanouk.vanlaer@arm.com // Managed to kill diod 47612187Sanouk.vanlaer@arm.com return; 47712187Sanouk.vanlaer@arm.com } 47812187Sanouk.vanlaer@arm.com 47912187Sanouk.vanlaer@arm.com} 48010391SAndreas.Sandberg@ARM.comVirtIO9PDiod * 48110391SAndreas.Sandberg@ARM.comVirtIO9PDiodParams::create() 48210391SAndreas.Sandberg@ARM.com{ 48310391SAndreas.Sandberg@ARM.com return new VirtIO9PDiod(this); 48410391SAndreas.Sandberg@ARM.com} 48510391SAndreas.Sandberg@ARM.com 48610391SAndreas.Sandberg@ARM.com 48710391SAndreas.Sandberg@ARM.com 48810391SAndreas.Sandberg@ARM.com 48910391SAndreas.Sandberg@ARM.comVirtIO9PSocket::VirtIO9PSocket(Params *params) 49010391SAndreas.Sandberg@ARM.com : VirtIO9PProxy(params), fdSocket(-1) 49110391SAndreas.Sandberg@ARM.com{ 49210391SAndreas.Sandberg@ARM.com} 49310391SAndreas.Sandberg@ARM.com 49410391SAndreas.Sandberg@ARM.comVirtIO9PSocket::~VirtIO9PSocket() 49510391SAndreas.Sandberg@ARM.com{ 49610391SAndreas.Sandberg@ARM.com} 49710391SAndreas.Sandberg@ARM.com 49810391SAndreas.Sandberg@ARM.comvoid 49910391SAndreas.Sandberg@ARM.comVirtIO9PSocket::startup() 50010391SAndreas.Sandberg@ARM.com{ 50110391SAndreas.Sandberg@ARM.com connectSocket(); 50210391SAndreas.Sandberg@ARM.com dataEvent.reset(new SocketDataEvent(*this, fdSocket, POLLIN)); 50310391SAndreas.Sandberg@ARM.com pollQueue.schedule(dataEvent.get()); 50410391SAndreas.Sandberg@ARM.com} 50510391SAndreas.Sandberg@ARM.com 50610391SAndreas.Sandberg@ARM.comvoid 50710391SAndreas.Sandberg@ARM.comVirtIO9PSocket::connectSocket() 50810391SAndreas.Sandberg@ARM.com{ 50910391SAndreas.Sandberg@ARM.com const Params &p(dynamic_cast<const Params &>(*params())); 51010391SAndreas.Sandberg@ARM.com 51110391SAndreas.Sandberg@ARM.com int ret; 51210391SAndreas.Sandberg@ARM.com struct addrinfo hints, *result; 51310391SAndreas.Sandberg@ARM.com memset(&hints, 0, sizeof(hints)); 51410391SAndreas.Sandberg@ARM.com hints.ai_family = AF_UNSPEC; 51510391SAndreas.Sandberg@ARM.com hints.ai_socktype = SOCK_STREAM; 51610391SAndreas.Sandberg@ARM.com hints.ai_flags = 0; 51710391SAndreas.Sandberg@ARM.com hints.ai_protocol = 0; 51810391SAndreas.Sandberg@ARM.com 51910391SAndreas.Sandberg@ARM.com if ((ret = getaddrinfo(p.server.c_str(), p.port.c_str(), 52010391SAndreas.Sandberg@ARM.com &hints, &result)) != 0) 52110391SAndreas.Sandberg@ARM.com panic("getaddrinfo: %s\n", gai_strerror(ret)); 52210391SAndreas.Sandberg@ARM.com 52310391SAndreas.Sandberg@ARM.com DPRINTF(VIO9P, "Connecting to 9p server '%s'.\n", p.server); 52410391SAndreas.Sandberg@ARM.com for (struct addrinfo *rp = result; rp; rp = rp->ai_next) { 52510391SAndreas.Sandberg@ARM.com fdSocket = socket(rp->ai_family, rp->ai_socktype, 52610391SAndreas.Sandberg@ARM.com rp->ai_protocol); 52710391SAndreas.Sandberg@ARM.com if (fdSocket == -1) { 52810391SAndreas.Sandberg@ARM.com continue; 52910391SAndreas.Sandberg@ARM.com } else if (connect(fdSocket, rp->ai_addr, rp->ai_addrlen) != -1) { 53010391SAndreas.Sandberg@ARM.com break; 53110391SAndreas.Sandberg@ARM.com } else { 53210391SAndreas.Sandberg@ARM.com close(fdSocket); 53310391SAndreas.Sandberg@ARM.com fdSocket = -1; 53410391SAndreas.Sandberg@ARM.com } 53510391SAndreas.Sandberg@ARM.com } 53610391SAndreas.Sandberg@ARM.com 53710391SAndreas.Sandberg@ARM.com freeaddrinfo(result); 53810391SAndreas.Sandberg@ARM.com 53910391SAndreas.Sandberg@ARM.com if (fdSocket == -1) 54010391SAndreas.Sandberg@ARM.com panic("Failed to connect to 9p server (%s:%s)", p.server, p.port); 54110391SAndreas.Sandberg@ARM.com} 54210391SAndreas.Sandberg@ARM.com 54310391SAndreas.Sandberg@ARM.comvoid 54410391SAndreas.Sandberg@ARM.comVirtIO9PSocket::socketDisconnect() 54510391SAndreas.Sandberg@ARM.com{ 54610391SAndreas.Sandberg@ARM.com panic("9P Socket disconnected!\n"); 54710391SAndreas.Sandberg@ARM.com} 54810391SAndreas.Sandberg@ARM.com 54910391SAndreas.Sandberg@ARM.comssize_t 55010391SAndreas.Sandberg@ARM.comVirtIO9PSocket::read(uint8_t *data, size_t len) 55110391SAndreas.Sandberg@ARM.com{ 55210391SAndreas.Sandberg@ARM.com assert(fdSocket != -1); 55310391SAndreas.Sandberg@ARM.com int ret; 55410391SAndreas.Sandberg@ARM.com 55510391SAndreas.Sandberg@ARM.com ret = ::recv(fdSocket, (void *)data, len, 0); 55610391SAndreas.Sandberg@ARM.com if (ret == 0) 55710391SAndreas.Sandberg@ARM.com socketDisconnect(); 55810391SAndreas.Sandberg@ARM.com 55910391SAndreas.Sandberg@ARM.com return ret < 0 ? -errno : ret; 56010391SAndreas.Sandberg@ARM.com} 56110391SAndreas.Sandberg@ARM.com 56210391SAndreas.Sandberg@ARM.comssize_t 56310391SAndreas.Sandberg@ARM.comVirtIO9PSocket::write(const uint8_t *data, size_t len) 56410391SAndreas.Sandberg@ARM.com{ 56510391SAndreas.Sandberg@ARM.com assert(fdSocket != -1); 56610391SAndreas.Sandberg@ARM.com int ret(::send(fdSocket, (const void *)data, len, 0)); 56710391SAndreas.Sandberg@ARM.com return ret < 0 ? -errno : ret; 56810391SAndreas.Sandberg@ARM.com} 56910391SAndreas.Sandberg@ARM.com 57010391SAndreas.Sandberg@ARM.comvoid 57110391SAndreas.Sandberg@ARM.comVirtIO9PSocket::SocketDataEvent::process(int revent) 57210391SAndreas.Sandberg@ARM.com{ 57310391SAndreas.Sandberg@ARM.com parent.serverDataReady(); 57410391SAndreas.Sandberg@ARM.com} 57510391SAndreas.Sandberg@ARM.com 57610391SAndreas.Sandberg@ARM.com 57710391SAndreas.Sandberg@ARM.comVirtIO9PSocket * 57810391SAndreas.Sandberg@ARM.comVirtIO9PSocketParams::create() 57910391SAndreas.Sandberg@ARM.com{ 58010391SAndreas.Sandberg@ARM.com return new VirtIO9PSocket(this); 58110391SAndreas.Sandberg@ARM.com} 582