Loading...
Searching...
No Matches
l4virtio
// vi:set ft=cpp: -*- Mode: C++ -*-
/* SPDX-License-Identifier: MIT */
/*
* Copyright (C) 2013-2024 Kernkonzept GmbH.
* Author(s): Alexander Warg <alexander.warg@kernkonzept.com>
* Matthias Lange <matthias.lange@kernkonzept.com>
*
*/
#pragma once
#include "virtio.h"
#include <l4/sys/capability>
#include <l4/sys/cxx/ipc_client>
#include <l4/re/dataspace>
#include <l4/sys/irq>
#include <l4/cxx/utils>
namespace L4virtio {
class Device :
public L4::Kobject_t<Device, L4::Icu, L4VIRTIO_PROTOCOL,
L4::Type_info::Demand_t<1> >
{
public:
typedef l4virtio_config_queue_t Config_queue;
struct Config_hdr : l4virtio_config_hdr_t
{
Config_queue *queues() const
{ return l4virtio_config_queues(this); }
template <typename T>
T *device_config() const
{
return static_cast<T*>(l4virtio_device_config(this));
}
int config_queue(unsigned num, L4::Cap<L4::Triggerable> out_notify,
L4::Cap<L4::Triggerable> in_notify,
l4_timeout_s to = L4_IPC_TIMEOUT_NEVER)
{
return send_cmd(L4VIRTIO_CMD_CFG_QUEUE | num,
out_notify, in_notify, to);
}
int notify_queue(unsigned num, L4::Cap<L4::Triggerable> out_notify,
L4::Cap<L4::Triggerable> in_notify,
l4_timeout_s to = L4_IPC_TIMEOUT_NEVER)
{
return send_cmd(L4VIRTIO_CMD_NOTIFY_QUEUE | num,
out_notify, in_notify, to);
}
bool fail_state() const
{
auto cfg_status = cxx::access_once(&status);
return cfg_status
& (L4VIRTIO_STATUS_FAILED | L4VIRTIO_STATUS_DEVICE_NEEDS_RESET);
}
int set_status(unsigned new_status, L4::Cap<L4::Triggerable> out_notify,
L4::Cap<L4::Triggerable> in_notify,
l4_timeout_s to = L4_IPC_TIMEOUT_NEVER)
{
return send_cmd(L4VIRTIO_CMD_SET_STATUS | new_status,
out_notify, in_notify, to);
}
int cfg_changed(unsigned reg, L4::Cap<L4::Triggerable> out_notify,
L4::Cap<L4::Triggerable> in_notify,
l4_timeout_s to = L4_IPC_TIMEOUT_NEVER)
{
return send_cmd(L4VIRTIO_CMD_CFG_CHANGED | reg,
out_notify, in_notify, to);
}
int send_cmd(unsigned command, L4::Cap<L4::Triggerable> out_notify,
L4::Cap<L4::Triggerable> in_notify,
l4_timeout_s to = L4_IPC_TIMEOUT_NEVER)
{
cxx::write_now(&cmd, command);
if (out_notify)
out_notify->trigger();
auto utcb = l4_utcb();
auto ipc_to = l4_timeout(L4_IPC_TIMEOUT_0, to);
do
{
if (in_notify)
if (l4_ipc_error(l4_ipc_receive(in_notify.cap(), utcb, ipc_to),
utcb) == L4_IPC_RETIMEOUT)
break;
}
while (cxx::access_once(&cmd));
return cxx::access_once(&cmd) ? -L4_EBUSY : L4_EOK;
}
};
L4_INLINE_RPC_OP(L4VIRTIO_OP_SET_STATUS, long,
set_status, (unsigned status));
L4_INLINE_RPC_OP(L4VIRTIO_OP_CONFIG_QUEUE, long,
config_queue, (unsigned queue));
L4_INLINE_RPC_OP(L4VIRTIO_OP_REGISTER_DS, long,
register_ds, (L4::Ipc::Cap<L4Re::Dataspace> ds_cap,
l4_uint64_t base, l4_umword_t offset,
l4_umword_t size));
L4_INLINE_RPC_OP(L4VIRTIO_OP_DEVICE_CONFIG, long, device_config,
(L4::Ipc::Out<L4::Cap<L4Re::Dataspace> > config_ds,
l4_addr_t *ds_offset));
L4_INLINE_RPC_OP(L4VIRTIO_OP_GET_DEVICE_IRQ, long, device_notification_irq,
(unsigned index, L4::Ipc::Out<L4::Cap<L4::Triggerable> > irq));
typedef L4::Typeid::Rpcs<set_status_t, config_queue_t, register_ds_t,
device_config_t, device_notification_irq_t>
Rpcs;
};
}
capability
L4::Cap related definitions.
L4::Cap_base::cap
l4_cap_idx_t cap() const noexcept
Return capability selector.
Definition capability.h:49
L4::Cap
C++ interface for capabilities.
Definition capability.h:224
L4::Ipc::Cap
Capability type for RPC interfaces (see L4::Cap<T>).
Definition ipc_types:699
L4::Kobject_t
Helper class to create an L4Re interface class that is derived from a single base class.
Definition __typeinfo.h:750
L4virtio::Device
IPC interface for virtio over L4 IPC.
Definition l4virtio:42
L4virtio::Device::register_ds
long register_ds(L4::Ipc::Cap< L4Re::Dataspace > ds_cap, l4_uint64_t base, l4_umword_t offset, l4_umword_t size)
Register a shared data space with VIRTIO host.
L4virtio::Device::device_notification_irq
long device_notification_irq(unsigned index, L4::Ipc::Out< L4::Cap< L4::Triggerable > > irq)
Get the notification interrupt corresponding to the given index.
L4virtio::Device::config_queue
long config_queue(unsigned queue)
Trigger queue configuration of the given queue.
L4virtio::Device::device_config
long device_config(L4::Ipc::Out< L4::Cap< L4Re::Dataspace > > config_ds, l4_addr_t *ds_offset)
Get the dataspace with the L4virtio configuration page.
L4virtio::Device::set_status
long set_status(unsigned status)
Write the VIRTIO status register.
dataspace
Dataspace interface.
l4_umword_t
unsigned long l4_umword_t
Unsigned machine word.
Definition l4int.h:40
l4_addr_t
unsigned long l4_addr_t
Address type.
Definition l4int.h:34
l4_uint64_t
unsigned long long l4_uint64_t
Unsigned 64bit value.
Definition l4int.h:31
L4_EBUSY
@ L4_EBUSY
Object currently busy, try later.
Definition err.h:42
L4_EOK
@ L4_EOK
Ok.
Definition err.h:32
l4_ipc_receive
l4_msgtag_t l4_ipc_receive(l4_cap_idx_t object, l4_utcb_t *utcb, l4_timeout_t timeout) L4_NOTHROW
Wait for a message from a specific source.
Definition ipc.h:602
l4_ipc_error
l4_umword_t l4_ipc_error(l4_msgtag_t tag, l4_utcb_t *utcb) L4_NOTHROW
Get the IPC error code for an IPC operation.
Definition ipc.h:629
L4_IPC_RETIMEOUT
@ L4_IPC_RETIMEOUT
Timeout during receive operation.
Definition ipc.h:89
L4_IPC_TIMEOUT_NEVER
#define L4_IPC_TIMEOUT_NEVER
never timeout
Definition __timeout.h:74
L4_IPC_TIMEOUT_0
#define L4_IPC_TIMEOUT_0
Timeout constants.
Definition __timeout.h:73
l4_timeout
L4_CONSTEXPR l4_timeout_t l4_timeout(l4_timeout_s snd, l4_timeout_s rcv) L4_NOTHROW
Combine send and receive timeout in a timeout.
Definition __timeout.h:213
l4_utcb
l4_utcb_t * l4_utcb(void) L4_NOTHROW L4_PURE
Get the UTCB address.
Definition utcb.h:346
l4virtio_device_config
void * l4virtio_device_config(l4virtio_config_hdr_t const *cfg)
Get the pointer to the device configuration.
Definition virtio.h:263
l4virtio_config_queues
L4_BEGIN_DECLS l4virtio_config_queue_t * l4virtio_config_queues(l4virtio_config_hdr_t const *cfg)
Get the pointer to the first queue config.
Definition virtio.h:252
L4VIRTIO_STATUS_FAILED
@ L4VIRTIO_STATUS_FAILED
Driver detected fatal error.
Definition virtio.h:94
L4VIRTIO_STATUS_DEVICE_NEEDS_RESET
@ L4VIRTIO_STATUS_DEVICE_NEEDS_RESET
Device detected fatal error.
Definition virtio.h:93
L4VIRTIO_OP_SET_STATUS
@ L4VIRTIO_OP_SET_STATUS
Write device status register.
Definition virtio.h:54
L4VIRTIO_OP_GET_DEVICE_IRQ
@ L4VIRTIO_OP_GET_DEVICE_IRQ
Retrieve device notification IRQ.
Definition virtio.h:58
L4VIRTIO_OP_DEVICE_CONFIG
@ L4VIRTIO_OP_DEVICE_CONFIG
Get device config page.
Definition virtio.h:57
L4VIRTIO_OP_CONFIG_QUEUE
@ L4VIRTIO_OP_CONFIG_QUEUE
Configure queue.
Definition virtio.h:55
L4VIRTIO_OP_REGISTER_DS
@ L4VIRTIO_OP_REGISTER_DS
Register shared memory with device.
Definition virtio.h:56
L4VIRTIO_CMD_NOTIFY_QUEUE
@ L4VIRTIO_CMD_NOTIFY_QUEUE
Configure a queue.
Definition virtio.h:125
L4VIRTIO_CMD_SET_STATUS
@ L4VIRTIO_CMD_SET_STATUS
Set the status register.
Definition virtio.h:122
L4VIRTIO_CMD_CFG_QUEUE
@ L4VIRTIO_CMD_CFG_QUEUE
Configure a queue.
Definition virtio.h:123
L4VIRTIO_CMD_CFG_CHANGED
@ L4VIRTIO_CMD_CFG_CHANGED
Device config changed.
Definition virtio.h:124
ipc_client
L4_INLINE_RPC_OP
#define L4_INLINE_RPC_OP(op, res, name, args, attr...)
Define an inline RPC call with specific opcode (type and callable).
Definition ipc_iface:497
irq
C++ Irq interface.
L4virtio
L4-VIRTIO Transport C++ API.
Definition l4virtio:26
cxx::write_now
void write_now(T *a, VAL &&val)
Write a value at an address exactly once.
Definition utils:71
cxx::access_once
T access_once(T const *a)
Read the value at an address at most once.
Definition utils:40
L4::Ipc::Out
Mark an argument as a output value in an RPC signature.
Definition ipc_types:31
L4::Typeid::Rpcs
Standard list of RPCs of an interface.
Definition __typeinfo.h:428
l4_timeout_s
Basic timeout specification.
Definition __timeout.h:40
l4virtio_config_hdr_t
L4-VIRTIO config header, provided in shared data space.
Definition virtio.h:133
l4virtio_config_queue_t
Queue configuration entry.
Definition virtio.h:224