L4Re – L4 Runtime Environment
virtio-block
1 // vi:ft=cpp
2 /* SPDX-License-Identifier: GPL-2.0-only or License-Ref-kk-custom */
3 /*
4  * Copyright (C) 2015-2020 Kernkonzept GmbH.
5  * Author(s): Sarah Hoffmann <sarah.hoffmann@kernkonzept.com>
6  *
7  */
8 #pragma once
9 
10 #include <l4/sys/factory>
11 #include <l4/sys/semaphore>
12 #include <l4/re/dataspace>
13 #include <l4/re/env>
14 #include <l4/re/util/unique_cap>
15 #include <l4/re/util/object_registry>
16 #include <l4/re/error_helper>
17 
18 #include <l4/util/atomic.h>
19 #include <l4/util/bitops.h>
20 #include <l4/l4virtio/l4virtio>
21 #include <l4/l4virtio/virtqueue>
22 #include <l4/l4virtio/virtio_block.h>
23 #include <l4/sys/consts.h>
24 
25 #include <cstring>
26 #include <vector>
27 #include <functional>
28 
29 namespace L4virtio { namespace Driver {
30 
31 
35 class Device
36 {
37 public:
60  void driver_connect(L4::Cap<L4virtio::Device> srvcap, bool manage_notify = true)
61  {
62  _device = srvcap;
63 
64  _next_devaddr = L4_SUPERPAGESIZE;
65 
66  auto *e = L4Re::Env::env();
67 
68  // Set up the virtio configuration page.
69 
70  _config_cap = L4Re::chkcap(L4Re::Util::make_unique_cap<L4Re::Dataspace>(),
71  "Allocate config dataspace capability");
72 
73  l4_addr_t ds_offset;
74  L4Re::chksys(_device->device_config(_config_cap.get(), &ds_offset),
75  "Request virtio config page");
76 
77  if (ds_offset & ~L4_PAGEMASK)
78  L4Re::chksys(-L4_EINVAL, "Virtio config page is page aligned.");
79 
80  L4Re::chksys(e->rm()->attach(&_config, L4_PAGESIZE,
81  L4Re::Rm::F::Search_addr | L4Re::Rm::F::RW,
82  L4::Ipc::make_cap_rw(_config_cap.get()), ds_offset,
83  L4_PAGESHIFT),
84  "Attach config dataspace");
85 
86  if (memcmp(&_config->magic, "virt", 4) != 0)
87  L4Re::chksys(-L4_ENODEV, "Device config has wrong magic value");
88 
89  if (_config->version != 2)
90  L4Re::chksys(-L4_ENODEV, "Invalid virtio version, must be 2");
91 
92  _device->set_status(0); // reset
93  int status = L4VIRTIO_STATUS_ACKNOWLEDGE;
94  _device->set_status(status);
95 
96  status |= L4VIRTIO_STATUS_DRIVER;
97  _device->set_status(status);
98 
99  if (_config->fail_state())
100  L4Re::chksys(-L4_EIO, "Device failure during initialisation.");
101 
102  // Set up the interrupt used to notify the device about events.
103  // (only supporting one interrupt with index 0 at the moment)
104 
105  _host_irq = L4Re::chkcap(L4Re::Util::make_unique_cap<L4::Irq>(),
106  "Allocate host IRQ capability");
107 
108  L4Re::chksys(_device->device_notification_irq(0, _host_irq.get()),
109  "Request device notification interrupt.");
110 
111  // Set up the interrupt to get notifications from the device.
112  // (only supporting one interrupt with index 0 at the moment)
113  if (manage_notify)
114  {
115  _driver_notification =
116  L4Re::chkcap(L4Re::Util::make_unique_cap<L4::Semaphore>(),
117  "Allocate notification capability");
118 
119  L4Re::chksys(l4_error(e->factory()->create(_driver_notification.get())),
120  "Create semaphore for notifications from device");
121 
122  L4Re::chksys(_device->bind(0, _driver_notification.get()),
123  "Bind driver notification interrupt");
124  }
125  }
126 
133  int bind_notification_irq(unsigned index, L4::Cap<L4::Triggerable> irq) const
134  { return l4_error(_device->bind(index, irq)); }
135 
137  bool fail_state() const { return _config->fail_state(); }
138 
148  {
149  if (!l4virtio_get_feature(_config->dev_features_map,
152  "Require Virtio 1.0 device; Legacy device not supported.");
153 
154  _config->driver_features_map[0] &= _config->dev_features_map[0];
155  _config->driver_features_map[1] &= _config->dev_features_map[1];
156 
157  _device->set_status(_config->status | L4VIRTIO_STATUS_FEATURES_OK);
158 
159  if (!(_config->status & L4VIRTIO_STATUS_FEATURES_OK))
160  L4Re::chksys(-L4_EINVAL, "Negotiation of device features.");
161 
162  _device->set_status(_config->status | L4VIRTIO_STATUS_DRIVER_OK);
163 
164  if (_config->fail_state())
165  return -L4_EIO;
166 
167  return L4_EOK;
168  }
169 
188  l4_umword_t size, l4_uint64_t *devaddr)
189  {
190  *devaddr = next_device_address(size);
191  return _device->register_ds(L4::Ipc::make_cap_rw(ds), *devaddr, offset, size);
192  }
193 
203  int config_queue(int num, unsigned size, l4_uint64_t desc_addr,
204  l4_uint64_t avail_addr, l4_uint64_t used_addr)
205  {
206  auto *queueconf = &_config->queues()[num];
207  queueconf->num = size;
208  queueconf->desc_addr = desc_addr;
209  queueconf->avail_addr = avail_addr;
210  queueconf->used_addr = used_addr;
211  queueconf->ready = 1;
212 
213  return _device->config_queue(num);
214  }
215 
221  int max_queue_size(int num) const
222  {
223  return _config->queues()[num].num_max;
224  }
225 
238  int send_and_wait(Virtqueue &queue, l4_uint16_t descno)
239  {
240  send(queue, descno);
241 
242  // wait for a reply, we assume that no other
243  // request will get in the way.
244  auto head = wait_for_next_used(queue);
245 
246  if (head < 0)
247  return head;
248 
249  return (head == descno) ? L4_EOK : -L4_EINVAL;
250  }
251 
259  int wait(int index) const
260  {
261  if (index != 0)
262  return -L4_EEXIST;
263 
264  return l4_ipc_error(_driver_notification->down(), l4_utcb());
265  }
266 
277  int wait_for_next_used(Virtqueue &queue) const
278  {
279  while (true)
280  {
281  int err = wait(0);
282 
283  if (err < 0)
284  return err;
285 
286  auto head = queue.find_next_used();
287  if (head != Virtqueue::Eoq) // spurious interrupt?
288  return head;
289  }
290  }
291 
298  void send(Virtqueue &queue, l4_uint16_t descno)
299  {
300  queue.enqueue_descriptor(descno);
301  if (!queue.no_notify_host())
302  _host_irq->trigger();
303  }
304 
305 private:
316  l4_uint64_t next_device_address(l4_umword_t size)
317  {
318  l4_umword_t ret;
319  size = l4_round_page(size);
320  do
321  {
322  ret = _next_devaddr;
323  if (l4_umword_t(~0) - ret < size)
324  L4Re::chksys(-L4_ENOMEM, "Out of device address space.");
325  }
326  while (!l4util_cmpxchg(&_next_devaddr, ret, ret + size));
327 
328  return ret;
329  }
330 
331 protected:
333  L4Re::Rm::Unique_region<L4virtio::Device::Config_hdr *> _config;
334  l4_umword_t _next_devaddr;
335  L4Re::Util::Unique_cap<L4::Semaphore> _driver_notification;
336 
337 private:
340 };
341 
342 
346 class Block_device : public Device
347 {
348 public:
349  typedef std::function<void(unsigned char)> Callback;
350 
351 private:
352  enum { Header_size = sizeof(l4virtio_block_header_t) };
353 
354  struct Request
355  {
356  l4_uint16_t tail;
357  Callback callback;
358 
359  Request() : tail(Virtqueue::Eoq), callback(0) {}
360  };
361 
362 public:
366  class Handle
367  {
368  friend Block_device;
369  l4_uint16_t head;
370 
371  explicit Handle(l4_uint16_t descno) : head(descno) {}
372 
373  public:
374  Handle() : head(Virtqueue::Eoq) {}
375  bool valid() const { return head != Virtqueue::Eoq; }
376  };
377 
398  l4_size_t usermem, void **userdata,
399  Ptr<void> &user_devaddr, l4_uint32_t fmask0 = -1U,
400  l4_uint32_t fmask1 = -1U)
401  {
402  // Contact device.
403  driver_connect(srvcap);
404 
405  if (_config->device != L4VIRTIO_ID_BLOCK)
406  L4Re::chksys(-L4_ENODEV, "Device is not a block device.");
407 
408  if (_config->num_queues != 1)
409  L4Re::chksys(-L4_EINVAL, "Invalid number of queues reported.");
410 
411  // Memory is shared in one large dataspace which contains queues,
412  // space for header/status and additional user-defined memory.
413  unsigned queuesz = max_queue_size(0);
414  l4_size_t totalsz = l4_round_page(usermem);
415 
416  l4_uint64_t const header_offset =
417  l4_round_size(_queue.total_size(queuesz),
419  l4_uint64_t const status_offset = header_offset + queuesz * Header_size;
420  l4_uint64_t const usermem_offset = l4_round_page(status_offset + queuesz);
421 
422  // reserve space for one header/status per descriptor
423  // TODO Should be reduced to 1/3 but this way no freelist is needed.
424  totalsz += usermem_offset;
425 
426  _queue_ds = L4Re::chkcap(L4Re::Util::make_unique_cap<L4Re::Dataspace>(),
427  "Allocate queue dataspace capability");
428  auto *e = L4Re::Env::env();
429  L4Re::chksys(e->mem_alloc()->alloc(totalsz, _queue_ds.get(),
432  "Allocate memory for virtio structures");
433 
434  // Now sort out which region goes where in the dataspace.
435  L4Re::chksys(e->rm()->attach(&_queue_region, totalsz,
436  L4Re::Rm::F::Search_addr | L4Re::Rm::F::RW,
437  L4::Ipc::make_cap_rw(_queue_ds.get()), 0,
438  L4_PAGESHIFT),
439  "Attach dataspace for virtio structures");
440 
441  l4_uint64_t devaddr;
442  L4Re::chksys(register_ds(_queue_ds.get(), 0, totalsz, &devaddr),
443  "Register queue dataspace with device");
444 
445  _queue.init_queue(queuesz, _queue_region.get());
446 
447  config_queue(0, queuesz, devaddr, devaddr + _queue.avail_offset(),
448  devaddr + _queue.used_offset());
449 
450  _header_addr = devaddr + header_offset;
451  _headers = reinterpret_cast<l4virtio_block_header_t *>(_queue_region.get()
452  + header_offset);
453 
454  _status_addr = devaddr + status_offset;
455  _status = _queue_region.get() + status_offset;
456 
457  user_devaddr = Ptr<void>(devaddr + usermem_offset);
458  if (userdata)
459  *userdata = _queue_region.get() + usermem_offset;
460 
461  // setup the callback mechanism
462  _pending.assign(queuesz, Request());
463 
464  // Finish handshake with device.
465  _config->driver_features_map[0] = fmask0;
466  _config->driver_features_map[1] = fmask1;
468  }
469 
474  {
475  return *_config->device_config<l4virtio_block_config_t>();
476  }
477 
487  Callback callback)
488  {
489  l4_uint16_t descno = _queue.alloc_descriptor();
490  if (descno == Virtqueue::Eoq)
491  return Handle(Virtqueue::Eoq);
492 
493  L4virtio::Virtqueue::Desc &desc = _queue.desc(descno);
494  Request &req = _pending[descno];
495 
496  // setup the header
497  l4virtio_block_header_t &head = _headers[descno];
498  head.type = type;
499  head.ioprio = 0;
500  head.sector = sector;
501 
502  // and put it in the descriptor
503  desc.addr = Ptr<void>(_header_addr + descno * Header_size);
504  desc.len = Header_size;
505  desc.flags.raw = 0; // no write, no indirect
506 
507  req.tail = descno;
508  req.callback = callback;
509 
510  return Handle(descno);
511  }
512 
524  int add_block(Handle handle, Ptr<void> addr, l4_uint32_t size)
525  {
526  l4_uint16_t descno = _queue.alloc_descriptor();
527  if (descno == Virtqueue::Eoq)
528  return -L4_EAGAIN;
529 
530  Request &req = _pending[handle.head];
531  L4virtio::Virtqueue::Desc &desc = _queue.desc(descno);
532  L4virtio::Virtqueue::Desc &prev = _queue.desc(req.tail);
533 
534  prev.next = descno;
535  prev.flags.next() = true;
536 
537  desc.addr = addr;
538  desc.len = size;
539  desc.flags.raw = 0;
540  if (_headers[handle.head].type > 0) // write or flush request
541  desc.flags.write() = true;
542 
543  req.tail = descno;
544 
545  return L4_EOK;
546  }
547 
560  int send_request(Handle handle)
561  {
562  // add the status bit
563  auto descno = _queue.alloc_descriptor();
564  if (descno == Virtqueue::Eoq)
565  return -L4_EAGAIN;
566 
567  Request &req = _pending[handle.head];
568  L4virtio::Virtqueue::Desc &desc = _queue.desc(descno);
569  L4virtio::Virtqueue::Desc &prev = _queue.desc(req.tail);
570 
571  prev.next = descno;
572  prev.flags.next() = true;
573 
574  desc.addr = Ptr<void>(_status_addr + descno);
575  desc.len = 1;
576  desc.flags.raw = 0;
577  desc.flags.write() = true;
578 
579  req.tail = descno;
580 
581  send(_queue, handle.head);
582 
583  return L4_EOK;
584  }
585 
596  {
597  // add the status bit
598  auto descno = _queue.alloc_descriptor();
599  if (descno == Virtqueue::Eoq)
600  return descno;
601 
602  L4virtio::Virtqueue::Desc &desc = _queue.desc(descno);
603  L4virtio::Virtqueue::Desc &prev = _queue.desc(_pending[handle.head].tail);
604 
605  prev.next = descno;
606  prev.flags.next() = true;
607 
608  desc.addr = Ptr<void>(_status_addr + descno);
609  desc.len = 1;
610  desc.flags.raw = 0;
611  desc.flags.write() = true;
612 
613  _pending[handle.head].tail = descno;
614 
615  int ret = send_and_wait(_queue, handle.head);
616  unsigned char status = _status[descno];
617  free_request(handle);
618 
619  if (ret < 0)
620  return ret;
621 
622  switch (status)
623  {
624  case L4VIRTIO_BLOCK_S_OK: return L4_EOK;
625  case L4VIRTIO_BLOCK_S_IOERR: return -L4_EIO;
626  case L4VIRTIO_BLOCK_S_UNSUPP: return -L4_ENOSYS;
627  }
628 
629  return -L4_EINVAL;
630  }
631 
632  void free_request(Handle handle)
633  {
634  if (handle.head != Virtqueue::Eoq
635  && _pending[handle.head].tail != Virtqueue::Eoq)
636  _queue.free_descriptor(handle.head, _pending[handle.head].tail);
637  _pending[handle.head].tail = Virtqueue::Eoq;
638  }
639 
647  {
648  for (l4_uint16_t descno = _queue.find_next_used();
649  descno != Virtqueue::Eoq;
650  descno = _queue.find_next_used()
651  )
652  {
653  if (descno >= _queue.num() || _pending[descno].tail == Virtqueue::Eoq)
654  L4Re::chksys(-L4_ENOSYS, "Bad descriptor number");
655 
656  unsigned char status = _status[descno];
657  free_request(Handle(descno));
658 
659  if (_pending[descno].callback)
660  _pending[descno].callback(status);
661  }
662  }
663 
664 protected:
666 
667 private:
668  L4Re::Rm::Unique_region<unsigned char *> _queue_region;
669  l4virtio_block_header_t *_headers;
670  unsigned char *_status;
671  l4_uint64_t _header_addr;
672  l4_uint64_t _status_addr;
673  Virtqueue _queue;
674  std::vector<Request> _pending;
675 };
676 
677 } }
#define L4_PAGESHIFT
Size of a page, log2-based.
Definition: consts.h:37
unsigned int l4_size_t
Unsigned size type.
Definition: l4int.h:35
bit manipulation functions
static Env const * env() noexcept
Returns the initial environment for the current task.
Definition: env:103
@ Continuous
Allocate physically contiguous memory.
Definition: mem_alloc:73
@ Pinned
Deprecated, use L4Re::Dma_space instead.
Definition: mem_alloc:74
l4_msgtag_t bind(unsigned irqnum, L4::Cap< Triggerable > irq, l4_utcb_t *utcb=l4_utcb()) noexcept
Bind an interrupt line of an interrupt controller to an interrupt object.
Definition: irq:285
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.
long device_notification_irq(unsigned index, L4::Ipc::Out< L4::Cap< L4::Triggerable > > irq)
Get the notification interrupt corresponding to the given index.
long config_queue(unsigned queue)
Trigger queue configuration of the given queue.
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.
long set_status(unsigned status)
Write the VIRTIO status register.
Handle to an ongoing request.
Definition: virtio-block:367
Simple class for accessing a virtio block device synchronously.
Definition: virtio-block:347
int send_request(Handle handle)
Process request asynchronously.
Definition: virtio-block:560
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.
Definition: virtio-block:524
int process_request(Handle handle)
Process request synchronously.
Definition: virtio-block:595
void setup_device(L4::Cap< L4virtio::Device > srvcap, l4_size_t usermem, void **userdata, Ptr< void > &user_devaddr, l4_uint32_t fmask0=-1U, l4_uint32_t fmask1=-1U)
Setup a connection to a device and set up shared memory.
Definition: virtio-block:397
void process_used_queue()
Process and free all items in the used queue.
Definition: virtio-block:646
l4virtio_block_config_t const & device_config() const
Return a reference to the device configuration.
Definition: virtio-block:473
Handle start_request(l4_uint64_t sector, l4_uint32_t type, Callback callback)
Start the setup of a new request.
Definition: virtio-block:486
Client-side implementation for a general virtio device.
Definition: virtio-block:36
int wait(int index) const
Wait for a notification from the device.
Definition: virtio-block:259
int max_queue_size(int num) const
Maximum queue size allowed by the device.
Definition: virtio-block:221
int wait_for_next_used(Virtqueue &queue) const
Wait for the next item to arrive in the used queue and return it.
Definition: virtio-block:277
int bind_notification_irq(unsigned index, L4::Cap< L4::Triggerable > irq) const
Register a triggerable to receive notifications from the device.
Definition: virtio-block:133
void driver_connect(L4::Cap< L4virtio::Device > srvcap, bool manage_notify=true)
Contacts the device and starts the initial handshake.
Definition: virtio-block:60
void send(Virtqueue &queue, l4_uint16_t descno)
Send a request to the device.
Definition: virtio-block:298
bool fail_state() const
Return true if the device is in a fail state.
Definition: virtio-block:137
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.
Definition: virtio-block:187
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.
Definition: virtio-block:203
int driver_acknowledge()
Finalize handshake with the device.
Definition: virtio-block:147
int send_and_wait(Virtqueue &queue, l4_uint16_t descno)
Send a request to the device and wait for it to be processed.
Definition: virtio-block:238
Driver-side implementation of a Virtqueue.
Definition: virtqueue:476
void free_descriptor(l4_uint16_t head, l4_uint16_t tail)
Free a chained list of descriptors in the descriptor queue.
Definition: virtqueue:636
void enqueue_descriptor(l4_uint16_t descno)
Enqueue a descriptor in the available ring.
Definition: virtqueue:579
Desc & desc(l4_uint16_t descno)
Return a reference to a descriptor in the descriptor table.
Definition: virtqueue:595
l4_uint16_t alloc_descriptor()
Allocate and return an unused descriptor from the descriptor table.
Definition: virtqueue:563
l4_uint16_t find_next_used(l4_uint32_t *len=nullptr)
Return the next finished block.
Definition: virtqueue:614
void init_queue(unsigned num, void *desc, void *avail, void *used)
Initialize this virtqueue.
Definition: virtqueue:527
Descriptor in the descriptor table.
Definition: virtqueue:96
l4_uint16_t next
Index of the next chained descriptor.
Definition: virtqueue:120
l4_uint32_t len
Length of described buffer.
Definition: virtqueue:118
Flags flags
Descriptor flags.
Definition: virtqueue:119
Ptr< void > addr
Address stored in descriptor.
Definition: virtqueue:117
unsigned long avail_offset() const
Get the offset of the available ring from the descriptor table.
Definition: virtqueue:329
static unsigned long total_size(unsigned num)
Calculate the total size for a virtqueue of the given dimensions.
Definition: virtqueue:251
unsigned long used_offset() const
Get the offset of the used ring from the descriptor table.
Definition: virtqueue:335
bool no_notify_host() const
Get the no notify flag of this queue.
Definition: virtqueue:431
unsigned num() const
Definition: virtqueue:409
Dataspace interface.
Environment interface.
Error helper.
Common factory related definitions.
unsigned long l4_umword_t
Unsigned machine word.
Definition: l4int.h:52
unsigned long l4_addr_t
Address type.
Definition: l4int.h:45
unsigned int l4_uint32_t
Unsigned 32bit value.
Definition: l4int.h:40
unsigned short int l4_uint16_t
Unsigned 16bit value.
Definition: l4int.h:38
unsigned long long l4_uint64_t
Unsigned 64bit value.
Definition: l4int.h:42
@ L4_EEXIST
Already exists.
Definition: err.h:54
@ L4_ENOSYS
No sys.
Definition: err.h:60
@ L4_EINVAL
Invalid argument.
Definition: err.h:56
@ L4_ENODEV
No such thing.
Definition: err.h:55
@ L4_EIO
I/O error.
Definition: err.h:46
@ L4_EOK
Ok.
Definition: err.h:43
@ L4_EAGAIN
Try again.
Definition: err.h:49
@ L4_ENOMEM
No memory.
Definition: err.h:50
long l4_error(l4_msgtag_t tag) L4_NOTHROW
Return error code of a system call return message tag or the tag label.
Definition: ipc.h:520
l4_umword_t l4_ipc_error(l4_msgtag_t tag, l4_utcb_t *utcb) L4_NOTHROW
Get the error code for an object invocation.
Definition: ipc.h:503
#define L4_SUPERPAGESIZE
Size of a large page.
Definition: consts.h:334
l4_addr_t l4_round_page(l4_addr_t address) L4_NOTHROW
Round address up to the next page.
Definition: consts.h:389
#define L4_PAGESIZE
Minimal page size (in bytes).
Definition: consts.h:307
#define L4_PAGEMASK
Mask for the page number.
Definition: consts.h:316
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.
Definition: consts.h:400
l4_utcb_t * l4_utcb(void) L4_NOTHROW L4_PURE
Get the UTCB address.
Definition: utcb.h:340
int l4util_cmpxchg(volatile l4_umword_t *dest, l4_umword_t cmp_val, l4_umword_t new_val)
Atomic compare and exchange (machine wide fields)
Definition: atomic.h:367
int l4util_bsr(l4_umword_t word)
Bit scan reverse.
Definition: bitops.h:299
struct l4virtio_block_header_t l4virtio_block_header_t
Header structure of a request for a block device.
@ L4VIRTIO_BLOCK_S_IOERR
IO error on device.
Definition: virtio_block.h:47
@ L4VIRTIO_BLOCK_S_UNSUPP
Operation is not supported.
Definition: virtio_block.h:48
@ L4VIRTIO_BLOCK_S_OK
Request finished successfully.
Definition: virtio_block.h:46
unsigned l4virtio_get_feature(l4_uint32_t *feature_map, unsigned feat)
Check if the given bit in a feature map is set.
Definition: virtio.h:276
@ L4VIRTIO_FEATURE_VERSION_1
Virtio protocol version 1 supported. Must be 1 for L4virtio.
Definition: virtio.h:93
@ L4VIRTIO_STATUS_DRIVER
Guest OS knows how to drive device.
Definition: virtio.h:82
@ L4VIRTIO_STATUS_ACKNOWLEDGE
Guest OS has found device.
Definition: virtio.h:81
@ L4VIRTIO_STATUS_FEATURES_OK
Driver has acknowledged feature set.
Definition: virtio.h:84
@ L4VIRTIO_STATUS_DRIVER_OK
Driver is set up.
Definition: virtio.h:83
@ L4VIRTIO_ID_BLOCK
General block device.
Definition: virtio.h:61
atomic operations header and generic implementations
L4::Detail::Unique_cap_impl< T, Smart_cap_auto< L4_FP_ALL_SPACES > > Unique_cap
Unique capability that implements automatic free and unmap of the capability selector.
Definition: unique_cap:54
long chksys(long err, char const *extra="", long ret=0)
Generate C++ exception on error.
Definition: error_helper:68
T chkcap(T &&cap, char const *extra="", long err=-L4_ENOMEM)
Check for valid capability or raise C++ exception.
Definition: error_helper:145
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.
Definition: ipc_types:634
L4-VIRTIO Transport C++ API.
Definition: virtio-block:29
Semaphore class definition.
@ Search_addr
Search for a suitable address range.
Definition: rm:105
write_bfm_t::Val write() const
Get the write bits ( 1 to 1 ) of raw.
Definition: virtqueue:112
next_bfm_t::Val next() const
Get the next bits ( 0 to 0 ) of raw.
Definition: virtqueue:110
l4_uint16_t raw
raw flags value of a virtio descriptor.
Definition: virtqueue:103
Device configuration for block devices.
Definition: virtio_block.h:81
Header structure of a request for a block device.
Definition: virtio_block.h:55
l4_uint32_t type
Kind of request, see L4virtio_block_operations.
Definition: virtio_block.h:56
l4_uint32_t ioprio
Priority (unused)
Definition: virtio_block.h:57
l4_uint64_t sector
First sector to read/write.
Definition: virtio_block.h:58
Unique_cap / Unique_del_cap.