16#include <l4/re/util/object_registry>
21#include <l4/l4virtio/client/l4virtio>
22#include <l4/l4virtio/l4virtio>
23#include <l4/l4virtio/virtqueue>
24#include <l4/l4virtio/virtio_block.h>
31namespace L4virtio {
namespace Driver {
39 typedef std::function<void(
unsigned char)> Callback;
49 Request() : tail(Virtqueue::Eoq), callback(0) {}
61 explicit Handle(
l4_uint16_t descno) : head(descno) {}
64 Handle() : head(Virtqueue::Eoq) {}
65 bool valid()
const {
return head != Virtqueue::Eoq; }
98 L4Re::Util::Dbg msg_dev = L4Re::Util::Dbg{2})
117 l4_uint64_t const status_offset = header_offset + queuesz * Header_size;
122 totalsz += usermem_offset;
128 "Allocate queue dataspace capability");
132 "Allocate memory for virtio structures");
133 _queue_ds = _ds.get();
137 if (qds->size() < totalsz)
147 "Attach dataspace for virtio structures");
151 "Register queue dataspace with device");
158 _header_addr = devaddr + header_offset;
162 _status_addr = devaddr + status_offset;
163 _status = _queue_region.
get() + status_offset;
165 user_devaddr = Ptr<void>(devaddr + usermem_offset);
167 *userdata = _queue_region.
get() + usermem_offset;
170 _pending.assign(queuesz, Request());
173 _config->driver_features_map[0] = fmask0;
174 _config->driver_features_map[1] = fmask1;
198 if (descno == Virtqueue::Eoq)
199 return Handle(Virtqueue::Eoq);
202 Request &req = _pending[descno];
212 desc.
len = Header_size;
216 req.callback = callback;
235 if (descno == Virtqueue::Eoq)
238 Request &req = _pending[handle.head];
253 auto type = _headers[handle.head].type;
277 auto descno = _queue.alloc_descriptor();
278 if (descno == Virtqueue::Eoq)
281 Request &req = _pending[handle.head];
295 send(_queue, handle.head);
318 auto descno = _queue.alloc_descriptor();
319 if (descno == Virtqueue::Eoq)
333 _pending[handle.head].tail = descno;
336 unsigned char status = _status[descno];
337 free_request(handle);
352 void free_request(Handle handle)
354 if (handle.head != Virtqueue::Eoq
355 && _pending[handle.head].tail != Virtqueue::Eoq)
357 _pending[handle.head].tail = Virtqueue::Eoq;
369 descno != Virtqueue::Eoq;
370 descno = _queue.find_next_used()
373 if (descno >= _queue.num() || _pending[descno].tail == Virtqueue::Eoq)
376 unsigned char status = _status[descno];
377 free_request(
Handle(descno));
379 if (_pending[descno].callback)
380 _pending[descno].callback(status);
391 unsigned char *_status;
395 std::vector<Request> _pending;
bit manipulation functions
static Env const * env() noexcept
Returns the initial environment for the current task.
@ Continuous
Allocate physically contiguous memory.
@ Pinned
Deprecated, use L4Re::Dma_space instead.
C++ interface for capabilities.
Handle to an ongoing request.
Simple class for accessing a virtio block device synchronously.
int send_request(Handle handle)
Process request asynchronously.
int add_block(Handle handle, Ptr< void > addr, l4_uint32_t size)
Add a data block to a request that has already been set up.
int process_request(Handle handle)
Process request synchronously.
l4virtio_block_config_t const & device_config() const
Return a reference to the device configuration.
void process_used_queue()
Process and free all items in the used queue.
void setup_device(L4::Cap< L4virtio::Device > srvcap, l4_size_t usermem, void **userdata, Ptr< void > &user_devaddr, L4::Cap< L4Re::Dataspace > qds=L4::Cap< L4Re::Dataspace >(), l4_uint32_t fmask0=-1U, l4_uint32_t fmask1=-1U, L4Re::Util::Dbg msg_dev=L4Re::Util::Dbg{2})
Establish a connection to the device and set up shared memory.
Handle start_request(l4_uint64_t sector, l4_uint32_t type, Callback callback)
Start the setup of a new request.
Client-side implementation for a general virtio device.
int max_queue_size(int num) const
Maximum queue size allowed by the device.
void driver_connect(L4::Cap< L4virtio::Device > srvcap, bool manage_notify=true)
Contacts the device and starts the initial handshake.
void send(Virtqueue &queue, l4_uint16_t descno)
Send a request to the device.
int register_ds(L4::Cap< L4Re::Dataspace > ds, l4_umword_t offset, l4_umword_t size, l4_uint64_t *devaddr)
Share a dataspace with the device.
int config_queue(int num, unsigned size, l4_uint64_t desc_addr, l4_uint64_t avail_addr, l4_uint64_t used_addr)
Send the virtqueue configuration to the device.
int driver_acknowledge()
Finalize handshake with the device.
int send_and_wait(Virtqueue &queue, l4_uint16_t descno)
Send a request to the device and wait for it to be processed.
Driver-side implementation of a Virtqueue.
void free_descriptor(l4_uint16_t head, l4_uint16_t tail)
Free a chained list of descriptors in the descriptor queue.
void init_queue(unsigned num, void *desc, void *avail, void *used, L4Re::Util::Dbg msg_dev=L4Re::Util::Dbg{2})
Initialize this virtqueue.
Pointer used in virtio descriptors.
Descriptor in the descriptor table.
l4_uint16_t next
Index of the next chained descriptor.
l4_uint32_t len
Length of described buffer.
Flags flags
Descriptor flags.
Ptr< void > addr
Address stored in descriptor.
unsigned long avail_offset() const
Get the offset of the available ring from the descriptor table.
static unsigned long total_size(unsigned num)
Calculate the total size for a virtqueue of the given dimensions.
unsigned long used_offset() const
Get the offset of the used ring from the descriptor table.
T get() const noexcept
Return the address.
Common factory related definitions.
unsigned int l4_size_t
Unsigned size type.
unsigned int l4_uint32_t
Unsigned 32bit value.
unsigned short int l4_uint16_t
Unsigned 16bit value.
unsigned long long l4_uint64_t
Unsigned 64bit value.
@ L4_EINVAL
Invalid argument.
@ L4_ENODEV
No such thing.
l4_addr_t l4_round_page(l4_addr_t address) L4_NOTHROW
Round address up to the next page.
#define L4_PAGESHIFT
Size of a page, log2-based.
l4_addr_t l4_round_size(l4_addr_t value, unsigned char bits) L4_NOTHROW
Round value up to the next alignment with bits size.
@ L4VIRTIO_BLOCK_T_GET_ID
Get device ID.
@ L4VIRTIO_BLOCK_T_IN
Read from device.
@ L4VIRTIO_BLOCK_S_IOERR
IO error on device.
@ L4VIRTIO_BLOCK_S_UNSUPP
Operation is not supported.
@ L4VIRTIO_BLOCK_S_OK
Request finished successfully.
@ L4VIRTIO_ID_BLOCK
General block device.
atomic operations header and generic implementations
Unique_cap< T > make_unique_cap()
Allocate a capability slot and wrap it in an Unique_cap.
L4::Detail::Unique_cap_impl< T, L4Re::Util::Smart_cap_auto< L4_FP_ALL_SPACES > > Unique_cap
Unique capability that implements automatic free and unmap of the capability selector.
T chkcap(T &&cap, char const *extra="", l4_ret_t err=-L4_ENOMEM)
Check for valid capability or raise C++ exception.
l4_ret_t chksys(l4_ret_t err, char const *extra="", l4_ret_t ret=0)
Generate C++ exception on error.
Cap< T > make_cap_rw(L4::Cap< T > cap) noexcept
Make an L4::Ipc::Cap<T> for the given capability with L4_CAP_FPAGE_RW rights.
L4-VIRTIO Transport C++ API.
Semaphore class definition.
@ RW
Readable and writable region.
@ Search_addr
Search for a suitable address range.
constexpr next_bfm_t::Val next() const
Get the next bits (0 to 0) of raw.
constexpr write_bfm_t::Val write() const
Get the write bits (1 to 1) of raw.
l4_uint16_t raw
raw flags value of a virtio descriptor.
Device configuration for block devices.
l4_uint32_t device
device ID
l4_uint32_t num_queues
number of virtqueues
Unique_cap / Unique_del_cap.