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),
149 DPRINTF(VIO9P,
"Got input data descriptor (len: %i)\n", desc->
size());
150 DPRINTF(VIO9P,
"\tPending transactions: %i\n",
parent.pendingTransactions.size());
157 auto data = std::make_unique<uint8_t[]>(data_size);
173 DPRINTF(VIO9P,
"Sending RMsg\n");
184 out_desc = out_desc->
next();
186 panic(
"sendRMsg: Framing error, no output descriptor.\n");
191 out_desc->
chainWrite(0, (uint8_t *)&header_out,
sizeof(header_out));
208 DPRINTF(VIO9P,
"P9Msg[len = %i, type = %s (%i), tag = %i]\n",
211 DPRINTF(VIO9P,
"P9Msg[len = %i, type = Unknown (%i), tag = %i]\n",
233 warn(
"Serializing VirtIO9Base device after device has been used. It is "
234 "likely that state will be lost, and that the device will cease "
248 warn(
"Unserializing VirtIO9Base device after device has been used. It is "
249 "likely that state has been lost, and that the device will cease "
258 const uint8_t *
data,
size_t size)
261 const size_t buf_size =
sizeof(
header) + size;
263 "header.len (%d) != header size (%d) + payload size (%d)!\n",
264 buf_size,
sizeof(
header), size);
267 auto buf =
static_cast<uint8_t*
>(malloc(buf_size));
269 memcpy(buf, &header_out,
sizeof(header_out));
270 memcpy(buf +
sizeof(header_out),
data, size);
282 const ssize_t payload_len =
header.len -
sizeof(
header);
284 panic(
"Payload length is negative!\n");
285 auto data = std::make_unique<uint8_t[]>(payload_len);
300 panic(
"readAll: Read failed: %i\n", -ret);
315 panic(
"writeAll: write failed: %i\n", -ret);
351 DPRINTF(VIO9P,
"Using diod at %s.\n",
p.diod);
353 panic_if(pipe(pipe_rfd) == -1,
"Failed to create DIOD read pipe: %s",
355 panic_if(pipe(pipe_wfd) == -1,
"Failed to create DIOD write pipe: %s",
362 int socket_id = socket(AF_UNIX, SOCK_STREAM, 0);
363 panic_if(socket_id == -1,
"Socket creation failed %i", errno);
366 struct sockaddr_un socket_address;
367 memset(&socket_address, 0,
sizeof(socket_address));
368 socket_address.sun_family = AF_UNIX;
370 const std::string socket_path =
simout.resolve(
p.socketPath);
372 " output directory an absolute path, else diod will fail!");
375 fatal_if(
sizeof(socket_address.sun_path) <= socket_path.length(),
376 "Incorrect length of socket path");
377 strncpy(socket_address.sun_path, socket_path.c_str(),
378 sizeof(socket_address.sun_path) - 1);
379 panic_if(bind(socket_id, (
struct sockaddr*)&socket_address,
380 sizeof(socket_address)) == -1,
381 "Socket binding to %i failed - most likely the output dir "
382 "and hence unused socket already exists.", socket_id);
393 auto diod_rfd_s = std::to_string(pipe_rfd[0]);
394 auto diod_wfd_s = std::to_string(pipe_wfd[1]);
397 execlp(
p.diod.c_str(),
p.diod.c_str(),
398 "-d", debug::VIO9P ?
"1" :
"0",
400 "-r", diod_rfd_s.c_str(),
401 "-w", diod_wfd_s.c_str(),
402 "-e",
p.root.c_str(),
405 "-l", socket_path.c_str(),
407 panic(
"Failed to execute diod to %s: %s", socket_path,
412 inform(
"Started diod with PID %u, you might need to manually kill "
422 return ret < 0 ? -errno : ret;
430 return ret < 0 ? -errno : ret;
447 perror(
"Killing diod process");
448 warn(
"Failed to kill diod using SIGTERM");
453 for (
unsigned i = 0;
i < 5;
i++) {
454 int wait_return = waitpid(
diod_pid, NULL, WNOHANG);
458 }
else if (wait_return == 0) {
464 warn(
"Failed in waitpid");
469 inform(
"Trying to kill diod with SIGKILL as SIGTERM failed \n");
471 perror(
"Killing diod process");
472 warn(
"Failed to kill diod using SIGKILL");
503 struct addrinfo hints, *result;
504 memset(&hints, 0,
sizeof(hints));
505 hints.ai_family = AF_UNSPEC;
506 hints.ai_socktype = SOCK_STREAM;
508 hints.ai_protocol = 0;
510 if ((ret = getaddrinfo(
p.server.c_str(),
p.port.c_str(),
511 &hints, &result)) != 0)
512 panic(
"getaddrinfo: %s\n", gai_strerror(ret));
514 DPRINTF(VIO9P,
"Connecting to 9p server '%s'.\n",
p.server);
515 for (
struct addrinfo *rp = result; rp; rp = rp->ai_next) {
516 fdSocket = socket(rp->ai_family, rp->ai_socktype,
520 }
else if (connect(
fdSocket, rp->ai_addr, rp->ai_addrlen) != -1) {
528 freeaddrinfo(result);
531 panic(
"Failed to connect to 9p server (%s:%s)",
p.server,
p.port);
537 panic(
"9P Socket disconnected!\n");
550 return ret < 0 ? -errno : ret;
558 return ret < 0 ? -errno : ret;
#define DDUMP(x, data, count)
DPRINTF is a debugging trace facility that allows one to selectively enable tracing statements.
static bool isAbsolute(const std::string &name)
Test if a path is absolute.
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.
VirtIO9PBase(const Params ¶ms)
void sendRMsg(const P9MsgHeader &header, const uint8_t *data, size_t size)
Send a 9p RPC message reply.
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.
static const DeviceId ID_9P
VirtIO device ID.
VirtIO9PBaseParams Params
static const FeatureBits F_MOUNT_TAG
Device provides a name of the resource in its configuration.
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
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.
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.
VirtIODeviceBase(const Params ¶ms, DeviceId id, size_t config_size, FeatureBits features)
void unserialize(CheckpointIn &cp) override
Unserialize an object.
void serialize(CheckpointOut &cp) const override
Serialize an object.
void registerQueue(VirtQueue &queue)
Register a new VirtQueue with the device model.
#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...
const Params & params() const
Copyright (c) 2024 Arm Limited 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.