L4Re Operating System Framework
Interface and Usage Documentation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
virtio-rng-device
1// vi:ft=cpp: -*- Mode: C++ -*-
2/*
3 * Copyright (C) 2024 Kernkonzept GmbH.
4 * Author(s): Martin Kuettler <martin.kuettler@kernkonzept.com>
5 *
6 * License: see LICENSE.spdx (in this directory or the directories above)
7 */
8
9#pragma once
10
11#include <l4/re/error_helper>
12#include <l4/sys/cxx/ipc_epiface>
13
14#include <l4/l4virtio/server/virtio>
15#include <l4/l4virtio/server/l4virtio>
16#include <l4/l4virtio/l4virtio>
17
18namespace L4virtio {
19namespace Svr {
20
32 template <typename Rnd_state, typename Epiface = L4virtio::Device>
34 public L4::Epiface_t<Virtio_rng<Rnd_state>, Epiface>
35{
36private:
37 enum
38 {
39 Num_request_queues = 1,
40 queue_size = 128,
41 };
42
43public:
44 using Random_state = Rnd_state;
45
51 class Host_irq : public L4::Irqep_t<Host_irq>
52 {
53 public:
54 explicit Host_irq(Virtio_rng *rng) : L4::Irqep_t<Host_irq>(), _rng(rng) {}
55
56 void handle_irq()
57 {
58 _rng->handle_queue();
59 }
60
61 private:
62 Virtio_rng *_rng;
63 };
64
69 {
70 public:
71 struct Data_buffer : public L4virtio::Svr::Data_buffer
72 {
73 Data_buffer() = default;
74 // This constructor is called from within start, so make it available.
75 Data_buffer(L4virtio::Svr::Driver_mem_region const *r,
78 {
79 pos = static_cast<char *>(r->local(d.addr));
80 left = d.len;
81 }
82 };
83
84 Request_processor(L4virtio::Svr::Virtqueue *q, Random_state *rnd,
85 Virtio_rng *rng)
86 : _q(q), _rnd(rnd), _rng(rng), _head() {}
87
88 bool init_queue()
89 {
90 auto r = _q->next_avail();
91
92 if (L4_UNLIKELY(!r))
93 return false;
94
95 _head = start(_rng->mem_info(), r, &_req);
96
97 return true;
98 }
99
100 void handle_request()
101 {
102 if (!_head)
103 if (!init_queue())
104 return;
105
106 for (;;)
107 {
108 auto const pos = reinterpret_cast<unsigned char *>(_req.pos);
109 _rnd->get_random(_req.left, pos);
110 _q->finish(_head, _rng, _req.left);
111 if (!init_queue())
112 break;
113 }
114 return;
115 }
116
117 private:
119 Random_state *_rnd;
120 Virtio_rng *_rng;
122 Data_buffer _req;
123 };
124
125 Virtio_rng(Random_state *rnd, L4::Registry_iface *registry)
126 : L4virtio::Svr::Device(&_dev_config),
127 _dev_config(L4VIRTIO_VENDOR_KK, L4VIRTIO_ID_RNG, Num_request_queues),
128 _rnd(rnd),
129 _host_irq(this),
130 _request_processor(&_q, rnd, this)
131 {
132 init_mem_info(2);
133 reset_queue_config(0, queue_size);
134 setup_queue(&_q, 0, queue_size);
135 registry->register_irq_obj(&_host_irq);
136
138 hf.ring_indirect_desc() = true;
139 _dev_config.host_features(0) = hf.raw;
140 _dev_config.set_host_feature(L4VIRTIO_FEATURE_VERSION_1);
141 _dev_config.reset_hdr();
142 }
143
144 void notify_queue(L4virtio::Svr::Virtqueue *)
145 {
146 if (_q.no_notify_guest())
147 return;
148
149 _dev_config.add_irq_status(L4VIRTIO_IRQ_STATUS_VRING);
150 L4Re::chkipc(_notify_guest_irq->trigger(), "trigger guest irq");
151 }
152
153 void handle_queue()
154 {
155 _request_processor.handle_request();
156 }
157
158 void reset() override
159 {
160 }
161
162 bool check_queues() override
163 {
164 return true;
165 }
166
167 int reconfig_queue(unsigned idx) override
168 {
169 if (idx != 0)
170 return -L4_ERANGE;
171
172 setup_queue(&_q, 0, queue_size);
173
174 return L4_EOK;
175 }
176
178 {
179 _dev_config.add_irq_status(L4VIRTIO_IRQ_STATUS_CONFIG);
180 _notify_guest_irq->trigger();
181 }
182
183 L4::Ipc_svr::Server_iface *server_iface() const override
184 {
186 }
187
188 long op_set_status(L4virtio::Device::Rights r, unsigned status)
189 {
190 return L4virtio::Svr::Device::op_set_status(r, status);
191 }
192
193 long op_config_queue(L4virtio::Device::Rights r, unsigned queue)
194 {
195 return L4virtio::Svr::Device::op_config_queue(r, queue);
196 }
197
198 long op_device_config(L4virtio::Device::Rights r,
200 l4_addr_t &ds_offset)
201 {
202 return L4virtio::Svr::Device::op_device_config(r, config_ds, ds_offset);
203 }
204
206 {
207 return L4::cap_cast<L4::Irq>(_host_irq.obj_cap());
208 }
209
211 {
212 _notify_guest_irq = L4Re::chkcap
213 (server_iface()->template rcv_cap<L4::Irq>(0));
214
215 L4Re::chksys(server_iface()->realloc_rcv_cap(0));
216 }
217
218
219private:
220 L4virtio::Svr::Dev_config_t<L4virtio::Svr::No_custom_data>_dev_config;
221 Random_state *_rnd;
223 Host_irq _host_irq;
224 L4::Cap<L4::Irq> _notify_guest_irq;
225 Request_processor _request_processor;
226};
227
228} // namespace Svr
229} // namespace L4virtio
C++ interface for capabilities.
Definition capability.h:219
Capability type for RPC interfaces (see L4::Cap<T>).
Definition ipc_types:699
Interface for server-loop related functions.
Definition ipc_epiface:37
Abstract interface for object registries.
Definition ipc_epiface:323
virtual L4::Cap< L4::Irq > register_irq_obj(L4::Epiface *o)=0
Register o as server-side object for asynchronous IRQs.
Server-side L4-VIRTIO device stub.
Definition l4virtio:796
bool setup_queue(Virtqueue *q, unsigned qn, unsigned num_max)
Enable/disable the specified queue.
Definition l4virtio:1041
void init_mem_info(unsigned num)
Initialize the memory region list to the given maximum.
Definition l4virtio:1006
Mem_list const * mem_info() const
Get the memory region list used for this device.
Definition l4virtio:892
void reset_queue_config(unsigned idx, unsigned num_max, bool inc_generation=false)
Trigger reset for the configuration space for queue idx.
Definition l4virtio:996
Encapsulate the state for processing a VIRTIO request.
Definition virtio:473
void start(DESC_MAN *dm, Virtqueue *ring, Virtqueue::Head_desc const &request, ARGS... args)
Start processing a new request.
Definition virtio:501
Handler for the Virtio requests.
A server implementation of the virtio-rng protocol.
void trigger_driver_config_irq() override
callback for triggering configuration change notification IRQ
void reset() override
reset callback, called for doing a device reset
L4::Cap< L4::Irq > device_notify_irq() const override
callback to gather the device notification IRQ (old-style)
int reconfig_queue(unsigned idx) override
callback for client queue-config request
bool check_queues() override
callback for checking if the queues at DRIVER_OK transition
void register_single_driver_irq() override
callback for registering a single guest IRQ for all queues (old-style)
VIRTIO request, essentially a descriptor from the available ring.
Definition virtio:94
Virtqueue implementation for the device.
Definition virtio:88
Request next_avail()
Get the next available descriptor from the available ring.
Definition virtio:136
void finish(Head_desc &d, QUEUE_OBSERVER *o, l4_uint32_t len=0)
Add a descriptor to the used ring, and notify an observer.
Definition virtio:240
Descriptor in the descriptor table.
Definition virtqueue:87
l4_uint32_t len
Length of described buffer.
Definition virtqueue:109
Ptr< void > addr
Address stored in descriptor.
Definition virtqueue:108
bool no_notify_guest() const
Get the no IRQ flag of this queue.
Definition virtqueue:413
Error helper.
unsigned long l4_addr_t
Address type.
Definition l4int.h:34
@ L4_ERANGE
Range error.
Definition err.h:48
@ L4_EOK
Ok.
Definition err.h:32
#define L4_UNLIKELY(x)
Expression is unlikely to execute.
Definition compiler.h:275
@ L4VIRTIO_FEATURE_VERSION_1
Virtio protocol version 1 supported. Must be 1 for L4virtio.
Definition virtio.h:99
@ L4VIRTIO_ID_RNG
Entropy source.
Definition virtio.h:66
@ L4VIRTIO_IRQ_STATUS_VRING
VRING IRQ pending flag.
Definition virtio.h:110
@ L4VIRTIO_IRQ_STATUS_CONFIG
CONFIG IRQ pending flag.
Definition virtio.h:111
long chksys(long err, char const *extra="", long ret=0)
Generate C++ exception on error.
Definition error_helper:72
T chkcap(T &&cap, char const *extra="", long err=-L4_ENOMEM)
Check for valid capability or raise C++ exception.
Definition error_helper:149
l4_msgtag_t chkipc(l4_msgtag_t tag, char const *extra="", l4_utcb_t *utcb=l4_utcb())
Test a message tag for IPC errors.
Definition error_helper:180
L4-VIRTIO Transport C++ API.
Definition l4virtio:26
Epiface implementation for Kobject-based interface implementations.
Definition ipc_epiface:504
Server_iface * server_iface() const
Get pointer to server interface at which the object is currently registered.
Definition ipc_epiface:213
Epiface implementation for interrupt handlers.
Definition ipc_epiface:283
Cap< L4::Irq > obj_cap() const
Get the (typed) capability to this object.
Definition ipc_epiface:294
l4_msgtag_t trigger(l4_utcb_t *utcb=l4_utcb()) noexcept
Trigger the object.
Definition irq:91
Abstract data buffer.
Definition virtio:307
l4_uint32_t left
Bytes left in buffer.
Definition virtio:309
char * pos
Current buffer position.
Definition virtio:308
Type for device feature bitmap.
Definition virtio:67
l4_uint32_t raw
The raw value of the features bitmap.
Definition virtio:68
constexpr ring_indirect_desc_bfm_t::Val ring_indirect_desc() const
Get the ring_indirect_desc bits ( 28 to 28 ) of raw.
Definition virtio:74