19 #include <l4/re/util/debug> 22 #include <l4/cxx/bitfield> 30 #ifdef __ARM_ARCH_7A__ 31 static inline void wmb() {
asm volatile (
"dmb" : : :
"memory"); }
32 static inline void rmb() {
asm volatile (
"dmb" : : :
"memory"); }
33 #elif defined(__ARM_ARCH_8A) 34 static inline void wmb() {
asm volatile (
"dsb ishst" : : :
"memory"); }
35 static inline void rmb() {
asm volatile (
"dsb ishld" : : :
"memory"); }
36 #elif defined(__mips__) 37 static inline void wmb() {
asm volatile (
"sync" : : :
"memory"); }
38 static inline void rmb() {
asm volatile (
"sync" : : :
"memory"); }
39 #elif defined(__amd64__) || defined (__i686__) 40 static inline void wmb() {
asm volatile (
"sfence" : : :
"memory"); }
41 static inline void rmb() {
asm volatile (
"lfence" : : :
"memory"); }
43 #warning Missing proper memory write barrier 44 static inline void wmb() {
asm volatile (
"" : : :
"memory"); }
45 static inline void rmb() {
asm volatile (
"" : : :
"memory"); }
55 template<
typename T >
108 CXX_BITFIELD_MEMBER( 0, 0, next, raw);
110 CXX_BITFIELD_MEMBER( 1, 1, write, raw);
112 CXX_BITFIELD_MEMBER( 2, 2, indirect, raw);
125 L4Re::Util::Dbg().printf(
"D[%04x]: %08llx (%x) f=%04x n=%04x\n",
127 len, (unsigned)flags.
raw, (
unsigned)next);
149 CXX_BITFIELD_MEMBER( 0, 0, no_irq, raw);
194 CXX_BITFIELD_MEMBER( 0, 0, no_notify, raw);
251 static_assert(Desc_align >= Avail_align,
252 "virtqueue alignment assumptions broken");
253 return l4_round_size(desc_size(num) + avail_size(num), Used_align)
274 {
return Desc_align; }
284 {
return 2 * num + 6; }
292 {
return Avail_align; }
303 {
return 8 * num + 6; }
311 {
return Used_align; }
320 return ((
char *) _used - (
char *) _desc)
328 {
return (
char const *)_avail - (
char const *)_desc; }
334 {
return (
char const *)_used - (
char const *)_desc; }
353 void setup(
unsigned num,
void *desc,
void *avail,
void *used)
360 _avail = (
Avail*)avail;
365 L4Re::Util::Dbg().printf(
"VQ[%p]: num=%d d:%p a:%p u:%p\n",
366 this, num, _desc, _avail, _used);
387 setup(num, (
void *)desc, (
void *)avail, (
void *)used);
396 { d->
dump(d - _desc); }
408 {
return _idx_mask + 1; }
502 _desc[d].next = d + 1;
503 _desc[num - 1].next = Eoq;
523 void init_queue(
unsigned num,
void *desc,
void *avail,
void *used)
525 setup(num, desc, avail, used);
526 initialize_rings(num);
540 setup_simple(num, base);
541 initialize_rings(num);
566 _next_free = _desc[idx].next;
578 if (descno > _idx_mask)
582 _avail->ring[_avail->idx & _idx_mask] = descno;
595 if (descno > _idx_mask)
598 return _desc[descno];
615 if (_current_avail == _used->idx)
618 auto elem = _used->ring[_current_avail++ & _idx_mask];
637 if (head > _idx_mask || tail > _idx_mask)
641 _desc[tail].next = _next_free;
static unsigned long desc_align()
Get the alignment in zero LSBs needed for the descriptor table.
Descriptor in the descriptor table.
Pointer used in virtio descriptors.
Used * _used
pointer to used ring.
static unsigned long avail_align()
Get the alignment in zero LSBs needed for the available ring.
void dump(Desc const *d) const
Dump descriptors for this queue.
l4_uint16_t raw
raw 16bit flags value of the available ring.
unsigned short int l4_uint16_t
Unsigned 16bit value.
void dump(unsigned idx) const
Dump a single descriptor.
Common L4 ABI Data Types.
l4_uint16_t raw
raw flags value as specified by virtio.
l4_uint16_t next
Index of the next chained descriptor.
bool no_notify_host() const
Get the no notify flag of this queue.
l4_addr_t l4_round_size(l4_umword_t value, unsigned char bits) L4_NOTHROW
Round value up to the next alignment with bits size.
void init_queue(unsigned num, void *desc, void *avail, void *used)
Initialize this virtqueue.
static unsigned long total_size(unsigned num)
Calculate the total size for a virtqueue of the given dimensions.
no_notify_bfm_t::Val no_notify() const
Get the no_notify bits ( 0 to 0 ) of raw .
Invalid_type
Type for making an invalid (NULL) Ptr.
Avail * _avail
pointer to available ring.
bool ready() const
Test if this queue is in working state.
Ptr(Invalid_type)
Make and invalid Ptr.
l4_uint16_t _current_avail
The life counter for the queue.
void disable()
Completely disable the queue.
void no_notify_host(bool value)
Set the no-notify flag for this queue.
Flags(l4_uint16_t v)
Make Flags from raw 16bit value.
Desc & desc(l4_uint16_t descno)
Return a reference to a descriptor in the descriptor table.
Exception for an abstract runtime error.
void initialize_rings(unsigned num)
Initialize the descriptor table and the index structures of this queue.
void free_descriptor(l4_uint16_t head, l4_uint16_t tail)
Free a chained list of descriptors in the descriptor queue.
Flags flags
flags of available ring
Type of available ring, this is read-only for the host.
l4_uint16_t raw
raw flags value of a virtio descriptor.
Virtqueue()
Create a disabled virtqueue.
static unsigned long used_align()
Get the alignment in zero LSBs needed for the used ring.
unsigned long used_offset() const
Get the offset of the used ring from the descriptor table.
Ptr< void > addr
Address stored in descriptor.
Ptr(l4_uint64_t vm_addr)
Make a Ptr from a raw 64bit address.
unsigned long total_size() const
Calculate the total size of this virtqueue.
void enqueue_descriptor(l4_uint16_t descno)
Enqueue a descriptor in the available ring.
Driver-side implementation of a Virtqueue.
l4_uint16_t get_tail_avail_idx() const
Get tail-available index stored in local state (for debugging).
l4_uint16_t get_avail_idx() const
Get available index from available ring (for debugging).
#define L4_LIKELY(x)
Expression is likely to execute.
l4_uint32_t id
descriptor index
l4_uint16_t idx
index of the last entry in the ring.
void setup(unsigned num, void *desc, void *avail, void *used)
Enable this queue.
Type for descriptor flags.
Used_elem(l4_uint16_t id, l4_uint32_t len)
Initialize a used ring element.
void setup_simple(unsigned num, void *ring)
Enable this queue.
Flags flags
Descriptor flags.
static unsigned long avail_size(unsigned num)
Calculate the size of the available ring for num entries.
Desc * _desc
pointer to descriptor table, NULL if queue is off.
no_irq_bfm_t::Val no_irq() const
Get the no_irq bits ( 0 to 0 ) of raw .
Type of an element of the used ring.
unsigned long avail_offset() const
Get the offset of the available ring from the descriptor table.
l4_uint32_t len
length field
Use to set a Ptr to invalid (NULL)
l4_uint16_t idx
available index written by guest
bool no_notify_guest() const
Get the no IRQ flag of this queue.
void init_queue(unsigned num, void *base)
Initialize this virtqueue.
static unsigned long desc_size(unsigned num)
Calculate the size of the descriptor table for num entries.
Flags(l4_uint16_t v)
make Flags from raw value
unsigned long long l4_uint64_t
Unsigned 64bit value.
l4_uint16_t find_next_used(l4_uint32_t *len=nullptr)
Return the next finished block.
l4_uint16_t alloc_descriptor()
Allocate and return an unused descriptor from the descriptor table.
L4-VIRTIO Transport C++ API.
l4_uint32_t len
Length of described buffer.
Flags flags
flags of the used ring.
unsigned long l4_addr_t
Address type.
Flags(l4_uint16_t v)
Make Flags from the raw value.
Flags of the available ring.
unsigned int l4_uint32_t
Unsigned 32bit value.
static unsigned long used_size(unsigned num)
Calculate the size of the used ring for num entries.
l4_uint16_t _idx_mask
mask used for indexing into the descriptor table and the rings.