42#include <netinet/in.h>
43#include <sys/socket.h>
55#include "debug/VIO9P.hh"
56#include "debug/VIO9PData.hh"
57#include "params/VirtIO9PBase.hh"
58#include "params/VirtIO9PDiod.hh"
59#include "params/VirtIO9PProxy.hh"
60#include "params/VirtIO9PSocket.hh"
78#define P9MSG(type, name) \
79 { (type), P9MsgInfo((type), "T" # name ) }, \
80 { (type + 1), P9MsgInfo((type + 1), "R" # name ) }
94 P9MSG(32, XATTRCREATE),
123 sizeof(
Config) + params.tag.size(),
149 DPRINTF(VIO9P,
"Got input data descriptor (len: %i)\n", desc->
size());
172 DPRINTF(VIO9P,
"Sending RMsg\n");
183 out_desc = out_desc->
next();
185 panic(
"sendRMsg: Framing error, no output descriptor.\n");
190 out_desc->
chainWrite(0, (uint8_t *)&header_out,
sizeof(header_out));
207 DPRINTF(VIO9P,
"P9Msg[len = %i, type = %s (%i), tag = %i]\n",
210 DPRINTF(VIO9P,
"P9Msg[len = %i, type = Unknown (%i), tag = %i]\n",
232 warn(
"Serializing VirtIO9Base device after device has been used. It is "
233 "likely that state will be lost, and that the device will cease "
247 warn(
"Unserializing VirtIO9Base device after device has been used. It is "
248 "likely that state has been lost, and that the device will cease "
257 const uint8_t *
data,
size_t size)
265 memcpy(out, (uint8_t *)&header_out,
sizeof(header_out));
266 memcpy(out +
sizeof(header_out),
data, size);
267 writeAll(out,
sizeof(header_out) + size);
279 panic(
"Payload length is negative!\n");
280 uint8_t
data[payload_len];
295 panic(
"readAll: Read failed: %i\n", -ret);
310 panic(
"writeAll: write failed: %i\n", -ret);
321 fd_to_diod(-1), fd_from_diod(-1), diod_pid(-1)
346 DPRINTF(VIO9P,
"Using diod at %s.\n",
p.diod);
348 panic_if(pipe(pipe_rfd) == -1,
"Failed to create DIOD read pipe: %s",
350 panic_if(pipe(pipe_wfd) == -1,
"Failed to create DIOD write pipe: %s",
357 int socket_id = socket(AF_UNIX, SOCK_STREAM, 0);
358 panic_if(socket_id == -1,
"Socket creation failed %i", errno);
361 struct sockaddr_un socket_address;
362 memset(&socket_address, 0,
sizeof(socket_address));
363 socket_address.sun_family = AF_UNIX;
367 " output directory an absolute path, else diod will fail!");
370 fatal_if(
sizeof(socket_address.sun_path) <= socket_path.length(),
371 "Incorrect length of socket path");
372 strncpy(socket_address.sun_path, socket_path.c_str(),
373 sizeof(socket_address.sun_path) - 1);
374 panic_if(bind(socket_id, (
struct sockaddr*)&socket_address,
375 sizeof(socket_address)) == -1,
376 "Socket binding to %i failed - most likely the output dir "
377 "and hence unused socket already exists.", socket_id);
388 auto diod_rfd_s = std::to_string(pipe_rfd[0]);
389 auto diod_wfd_s = std::to_string(pipe_wfd[1]);
392 execlp(
p.diod.c_str(),
p.diod.c_str(),
393 "-d", debug::VIO9P ?
"1" :
"0",
395 "-r", diod_rfd_s.c_str(),
396 "-w", diod_wfd_s.c_str(),
397 "-e",
p.root.c_str(),
400 "-l", socket_path.c_str(),
402 panic(
"Failed to execute diod to %s: %s", socket_path,
407 inform(
"Started diod with PID %u, you might need to manually kill "
417 return ret < 0 ? -errno : ret;
425 return ret < 0 ? -errno : ret;
442 perror(
"Killing diod process");
443 warn(
"Failed to kill diod using SIGTERM");
448 for (
unsigned i = 0;
i < 5;
i++) {
449 int wait_return = waitpid(
diod_pid, NULL, WNOHANG);
453 }
else if (wait_return == 0) {
459 warn(
"Failed in waitpid");
464 inform(
"Trying to kill diod with SIGKILL as SIGTERM failed \n");
466 perror(
"Killing diod process");
467 warn(
"Failed to kill diod using SIGKILL");
498 struct addrinfo hints, *result;
499 memset(&hints, 0,
sizeof(hints));
500 hints.ai_family = AF_UNSPEC;
501 hints.ai_socktype = SOCK_STREAM;
503 hints.ai_protocol = 0;
505 if ((ret = getaddrinfo(
p.server.c_str(),
p.port.c_str(),
506 &hints, &result)) != 0)
507 panic(
"getaddrinfo: %s\n", gai_strerror(ret));
509 DPRINTF(VIO9P,
"Connecting to 9p server '%s'.\n",
p.server);
510 for (
struct addrinfo *rp = result; rp; rp = rp->ai_next) {
511 fdSocket = socket(rp->ai_family, rp->ai_socktype,
515 }
else if (connect(
fdSocket, rp->ai_addr, rp->ai_addrlen) != -1) {
523 freeaddrinfo(result);
526 panic(
"Failed to connect to 9p server (%s:%s)",
p.server,
p.port);
532 panic(
"9P Socket disconnected!\n");
545 return ret < 0 ? -errno : ret;
553 return ret < 0 ? -errno : ret;
#define DDUMP(x, data, count)
DPRINTF is a debugging trace facility that allows one to selectively enable tracing statements.
std::string resolve(const std::string &name) const
Returns relative file names prepended with name of this directory.
static bool isAbsolute(const std::string &name)
Test if a path is absolute.
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
T get(ByteOrder endian) const
Get the data in the packet byte swapped from the specified endianness.
VirtIO descriptor (chain) wrapper.
bool isOutgoing() const
Check if this is a write-only descriptor (outgoing data).
size_t size() const
Retrieve the size of this descriptor.
void chainRead(size_t offset, uint8_t *dst, size_t size) const
Read the contents of a descriptor chain.
VirtDescriptor * next() const
Get the pointer to the next descriptor in a chain.
void chainWrite(size_t offset, const uint8_t *src, size_t size)
Write to a descriptor chain.
void onNotifyDescriptor(VirtDescriptor *desc)
Notify queue of pending incoming descriptor.
This class implements a VirtIO transport layer for the 9p network file system.
VirtIO9PBase(const Params ¶ms)
void sendRMsg(const P9MsgHeader &header, const uint8_t *data, size_t size)
Send a 9p RPC message reply.
virtual void recvTMsg(const P9MsgHeader &header, const uint8_t *data, size_t size)=0
Handle incoming 9p RPC message.
std::unique_ptr< Config, void(*)(void *p)> config
Currently active configuration (host byte order)
void readConfig(PacketPtr pkt, Addr cfgOffset)
Read from the configuration space of a device.
void dumpMsg(const P9MsgHeader &header, const uint8_t *data, size_t size)
Dump a 9p RPC message on the debug output.
std::map< P9Tag, VirtDescriptor * > pendingTransactions
Map between 9p transaction tags and descriptors where they appeared.
VirtIO9PBaseParams Params
void startDiod()
Start diod and setup the communication pipes.
void startup()
startup() is the final initialization call before simulation.
int fd_from_diod
fd for data pipe coming from diod (read end)
int diod_pid
PID of diod process.
ssize_t read(uint8_t *data, size_t len)
Read data from the server behind the proxy.
VirtIO9PDiod(const Params ¶ms)
ssize_t write(const uint8_t *data, size_t len)
Write data to the server behind the proxy.
VirtIO9PDiodParams Params
int fd_to_diod
fd for data pipe going to diod (write end)
void terminateDiod()
Kill the diod child process at the end of the simulation.
std::unique_ptr< DiodDataEvent > dataEvent
VirtIO 9p proxy base class.
virtual ssize_t read(uint8_t *data, size_t len)=0
Read data from the server behind the proxy.
virtual ssize_t write(const uint8_t *data, size_t len)=0
Write data to the server behind the proxy.
void recvTMsg(const P9MsgHeader &header, const uint8_t *data, size_t size) override
Handle incoming 9p RPC message.
void writeAll(const uint8_t *data, size_t len)
Convenience function that writes exactly len bytes.
void readAll(uint8_t *data, size_t len)
Convenience function that reads exactly len bytes.
bool deviceUsed
Bool to track if the device has been used or not.
VirtIO9PProxyParams Params
void unserialize(CheckpointIn &cp) override
Unserialize an object.
VirtIO9PProxy(const Params ¶ms)
void serverDataReady()
Notification of pending data from server.
void serialize(CheckpointOut &cp) const override
Serialize an object.
virtual ~VirtIO9PSocket()
std::unique_ptr< SocketDataEvent > dataEvent
ssize_t read(uint8_t *data, size_t len)
Read data from the server behind the proxy.
VirtIO9PSocketParams Params
void startup()
startup() is the final initialization call before simulation.
void socketDisconnect()
9p server disconnect notification
int fdSocket
Socket connected to the 9p server.
VirtIO9PSocket(const Params ¶ms)
ssize_t write(const uint8_t *data, size_t len)
Write data to the server behind the proxy.
void connectSocket()
Try to resolve the server name and connect to the 9p server.
Base class for all VirtIO-based devices.
void kick()
Inform the guest of available buffers.
ByteOrder byteOrder
The byte order of the queues, descriptors, etc.
void readConfigBlob(PacketPtr pkt, Addr cfgOffset, const uint8_t *cfg)
Read configuration data from a device structure.
const size_t configSize
Size of the device's configuration space.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
virtual void reset()
Driver-request device reset.
void serialize(CheckpointOut &cp) const override
Serialize an object.
void registerQueue(VirtQueue &queue)
Register a new VirtQueue with the device model.
void produceDescriptor(VirtDescriptor *desc, uint32_t len)
Send a descriptor chain to the guest.
#define P9MSG(type, name)
#define panic(...)
This implements a cprintf based panic() function.
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
void schedule(PollEvent *event)
const Params & params() const
ByteOrder byteOrder(const ThreadContext *tc)
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
T htop9(T v)
Convert host byte order to p9 byte order (LE)
std::ostream CheckpointOut
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
T p9toh(T v)
Convert p9 byte order (LE) to host byte order.
static const P9MsgInfoMap p9_msg_info
std::map< P9MsgType, P9MsgInfo > P9MsgInfoMap
T htog(T value, ByteOrder guest_byte_order)
void registerExitCallback(const std::function< void()> &callback)
Register an exit callback.
#define UNSERIALIZE_SCALAR(scalar)
#define SERIALIZE_SCALAR(scalar)
P9MsgInfo(P9MsgType _type, std::string _name)
VirtIO 9p configuration structure.