libvirtqueue: Set queue size on initialization

A virtqueue's queue size specifies the length of each ring and the
length of the descriptor table.
diff --git a/libvirtqueue/CMakeLists.txt b/libvirtqueue/CMakeLists.txt
index f780863..eaecf4a 100644
--- a/libvirtqueue/CMakeLists.txt
+++ b/libvirtqueue/CMakeLists.txt
@@ -19,4 +19,4 @@
 add_library(virtqueue STATIC EXCLUDE_FROM_ALL src/virtqueue.c)
 
 target_include_directories(virtqueue PUBLIC include)
-target_link_libraries(virtqueue muslc)
+target_link_libraries(virtqueue PUBLIC muslc PRIVATE utils)
diff --git a/libvirtqueue/include/virtqueue.h b/libvirtqueue/include/virtqueue.h
index c26b571..ac3c6da 100644
--- a/libvirtqueue/include/virtqueue.h
+++ b/libvirtqueue/include/virtqueue.h
@@ -14,11 +14,9 @@
 
 #include <stdint.h>
 
-#define RING_SIZE       256
-#define DESC_TABLE_SIZE 256
 
-#define VQ_DEV_POLL(vq) ((((vq)->a_ring_last_seen + 1) & (RING_SIZE - 1)) != (vq)->avail_ring->idx)
-#define VQ_DRV_POLL(vq) ((((vq)->u_ring_last_seen + 1) & (RING_SIZE - 1)) != (vq)->used_ring->idx)
+#define VQ_DEV_POLL(vq) ((((vq)->a_ring_last_seen + 1) & ((vq)->queue_len - 1)) != (vq)->avail_ring->idx)
+#define VQ_DRV_POLL(vq) ((((vq)->u_ring_last_seen + 1) & ((vq)->queue_len - 1)) != (vq)->used_ring->idx)
 
 /* Flags for the buffers in the descriptor table */
 typedef enum vq_flags {
@@ -31,7 +29,7 @@
 typedef struct vq_vring_avail {
     uint16_t flags;             /* Interrupt suppression flag */
     uint16_t idx;               /* Index of the next free entry in the ring */
-    uint16_t ring[RING_SIZE];   /* The ring of descriptor table entries */
+    uint16_t ring[];   /* The ring of descriptor table entries */
 } vq_vring_avail_t;
 
 /* Element of a used ring buffer */
@@ -44,7 +42,7 @@
 typedef struct vq_vring_used {
     uint16_t flags;                             /* Interrupt suppression flag */
     uint16_t idx;                               /* Index of the next free entry in the ring */
-    struct vq_vring_used_elem ring[RING_SIZE];  /* The ring of descriptor table entries */
+    struct vq_vring_used_elem ring[];  /* The ring of descriptor table entries */
 } vq_vring_used_t;
 
 /* Entry in the descriptor table */
@@ -66,6 +64,7 @@
     void (*notify)(void);       /* Notify function to wake-up driver side */
     void *cookie;               /* User-defined cookie */
 
+    unsigned queue_len;         /* The number of entries in rings and descriptor table */
     unsigned a_ring_last_seen;  /* Index of the last seen element in the available ring */
 
     struct vq_vring_avail *avail_ring; /* The available ring */
@@ -78,6 +77,7 @@
     void (*notify)(void);       /* Notify function to wake-up device side */
     void *cookie;               /* User-defined cookie */
 
+    unsigned queue_len;         /* The number of entries in rings and descriptor table */
     unsigned free_desc_head;    /* The head of the free list in the descriptor table */
     unsigned u_ring_last_seen;  /* Index of the last seen element in the used ring */
 
@@ -88,30 +88,32 @@
 
 /* Initialise a driver-side virtqueue.
  * @param vq the driver virtqueue
+ * @param queue_len the length of rings and descriptor table
  * @param avail_ring pointer to the shared available ring
  * @param used_ring pointer to the shared used ring
  * @param desc pointer to the shared descriptor table
  * @param notify the notify function to wake up device side
  * @param cookie user's cookie
  */
-void virtqueue_init_driver(virtqueue_driver_t *vq, vq_vring_avail_t *avail_ring,
+void virtqueue_init_driver(virtqueue_driver_t *vq, unsigned queue_len, vq_vring_avail_t *avail_ring,
                            vq_vring_used_t *used_ring, vq_vring_desc_t *desc, void (*notify)(void),
                            void *cookie);
 
 /* Initialise a device-side virtqueue.
  * @param vq the device virtqueue
+ * @param queue_len the length of rings and descriptor table
  * @param avail_ring pointer to the shared available ring
  * @param used_ring pointer to the shared used ring
  * @param desc pointer to the shared descriptor table
  * @param notify the notify function to wake up driver side
  * @param cookie user's cookie
  */
-void virtqueue_init_device(virtqueue_device_t *vq, vq_vring_avail_t *avail_ring,
+void virtqueue_init_device(virtqueue_device_t *vq, unsigned queue_len, vq_vring_avail_t *avail_ring,
                            vq_vring_used_t *used_ring, vq_vring_desc_t *desc, void (*notify)(void),
                            void *cookie);
 
 /* Initialise the descriptor table (create the free list) */
-void virtqueue_init_desc_table(vq_vring_desc_t *table);
+void virtqueue_init_desc_table(vq_vring_desc_t *table, unsigned queue_len);
 
 /* Initialise the available ring */
 void virtqueue_init_avail_ring(vq_vring_avail_t *ring);
diff --git a/libvirtqueue/src/virtqueue.c b/libvirtqueue/src/virtqueue.c
index 5ffb79d..e0631a0 100644
--- a/libvirtqueue/src/virtqueue.c
+++ b/libvirtqueue/src/virtqueue.c
@@ -10,26 +10,39 @@
  * @TAG(DATA61_BSD)
  */
 
+#include <utils/util.h>
 #include <virtqueue.h>
 
-void virtqueue_init_driver(virtqueue_driver_t *vq, vq_vring_avail_t *avail_ring,
+void virtqueue_init_driver(virtqueue_driver_t *vq, unsigned queue_len, vq_vring_avail_t *avail_ring,
                            vq_vring_used_t *used_ring, vq_vring_desc_t *desc, void (*notify)(void),
                            void *cookie)
 {
+    if (!IS_POWER_OF_2(queue_len)) {
+        ZF_LOGE("Invalid queue_len: %d, must be a power of 2.", queue_len);
+    }
     vq->free_desc_head = 0;
-    vq->u_ring_last_seen = RING_SIZE - 1;
+    vq->queue_len = queue_len;
+    vq->u_ring_last_seen = vq->queue_len - 1;
     vq->avail_ring = avail_ring;
     vq->used_ring = used_ring;
     vq->desc_table = desc;
     vq->notify = notify;
     vq->cookie = cookie;
+    virtqueue_init_desc_table(desc, vq->queue_len);
+    virtqueue_init_avail_ring(avail_ring);
+    virtqueue_init_used_ring(used_ring);
+
 }
 
-void virtqueue_init_device(virtqueue_device_t *vq, vq_vring_avail_t *avail_ring,
+void virtqueue_init_device(virtqueue_device_t *vq, unsigned queue_len, vq_vring_avail_t *avail_ring,
                            vq_vring_used_t *used_ring, vq_vring_desc_t *desc, void (*notify)(void),
                            void *cookie)
 {
-    vq->a_ring_last_seen = RING_SIZE - 1;
+    if (!IS_POWER_OF_2(queue_len)) {
+        ZF_LOGE("Invalid queue_len: %d, must be a power of 2.", queue_len);
+    }
+    vq->queue_len = queue_len;
+    vq->a_ring_last_seen = vq->queue_len - 1;
     vq->avail_ring = avail_ring;
     vq->used_ring = used_ring;
     vq->desc_table = desc;
@@ -37,10 +50,10 @@
     vq->cookie = cookie;
 }
 
-void virtqueue_init_desc_table(vq_vring_desc_t *table)
+void virtqueue_init_desc_table(vq_vring_desc_t *table, unsigned queue_len)
 {
     unsigned i;
-    for (i = 0; i < DESC_TABLE_SIZE; i++) {
+    for (i = 0; i < queue_len; i++) {
         table[i].addr = 0;
         table[i].len = 0;
         table[i].flags = 0;
@@ -67,7 +80,7 @@
     vq_vring_desc_t *desc;
 
     new = vq->free_desc_head;
-    if (new == DESC_TABLE_SIZE) {
+    if (new == vq->queue_len) {
         return new;
     }
     vq->free_desc_head = vq->desc_table[new].next;
@@ -79,9 +92,9 @@
 
     desc->len = len;
     desc->flags = flag;
-    desc->next = DESC_TABLE_SIZE;
+    desc->next = vq->queue_len;
 
-    if (prev != DESC_TABLE_SIZE) {
+    if (prev < vq->queue_len) {
         desc = vq->desc_table + prev;
         desc->next = new;
     }
@@ -107,7 +120,7 @@
 
 static void vq_free_chain(virtqueue_driver_t *vq, unsigned head)
 {
-    while (head != DESC_TABLE_SIZE) {
+    while (head != vq->queue_len) {
         vq->desc_table[head].next = vq->free_desc_head;
         vq->free_desc_head = head;
         head = vq->desc_table[head].next;
@@ -120,23 +133,23 @@
     unsigned idx;
 
     /* If descriptor table full */
-    if ((idx = vq_add_desc(vq, buf, len, flag, obj->cur)) == DESC_TABLE_SIZE) {
+    if ((idx = vq_add_desc(vq, buf, len, flag, obj->cur)) == vq->queue_len) {
         return 0;
     }
     obj->cur = idx;
 
     /* If this is the first buffer in the descriptor chain */
-    if (obj->first == DESC_TABLE_SIZE) {
+    if (obj->first >= vq->queue_len) {
         obj->first = idx;
         vq->avail_ring->ring[vq->avail_ring->idx] = idx;
-        vq->avail_ring->idx = (vq->avail_ring->idx + 1) & (RING_SIZE - 1);
+        vq->avail_ring->idx = (vq->avail_ring->idx + 1) & (vq->queue_len - 1);
     }
     return 1;
 }
 
 int virtqueue_get_used_buf(virtqueue_driver_t *vq, virtqueue_ring_object_t *obj, uint32_t *len)
 {
-    unsigned next = (vq->u_ring_last_seen + 1) & (RING_SIZE - 1);
+    unsigned next = (vq->u_ring_last_seen + 1) & (vq->queue_len - 1);
 
     if (next == vq->used_ring->idx) {
         return 0;
@@ -154,13 +167,13 @@
 
     vq->used_ring->ring[cur].id = robj->first;
     vq->used_ring->ring[cur].len = len;
-    vq->used_ring->idx = (cur + 1) & (RING_SIZE - 1);
+    vq->used_ring->idx = (cur + 1) & (vq->queue_len - 1);
     return 1;
 }
 
 int virtqueue_get_available_buf(virtqueue_device_t *vq, virtqueue_ring_object_t *robj)
 {
-    unsigned next = (vq->a_ring_last_seen + 1) & (RING_SIZE - 1);
+    unsigned next = (vq->a_ring_last_seen + 1) & (vq->queue_len - 1);
 
     if (next == vq->avail_ring->idx) {
         return 0;
@@ -173,8 +186,8 @@
 
 void virtqueue_init_ring_object(virtqueue_ring_object_t *obj)
 {
-    obj->cur = DESC_TABLE_SIZE;
-    obj->first = DESC_TABLE_SIZE;
+    obj->cur = (uint32_t) -1;
+    obj->first = (uint32_t) -1;
 }
 
 uint32_t virtqueue_scattered_available_size(virtqueue_device_t *vq, virtqueue_ring_object_t *robj)
@@ -182,7 +195,7 @@
     uint32_t ret = 0;
     unsigned cur = robj->first;
 
-    while (cur != DESC_TABLE_SIZE) {
+    while (cur < vq->queue_len) {
         ret += vq->desc_table[cur].len;
         cur = vq->desc_table[cur].next;
     }
@@ -194,7 +207,7 @@
 {
     unsigned idx = robj->cur;
 
-    if (idx == DESC_TABLE_SIZE) {
+    if (idx >= vq->queue_len) {
         return 0;
     }
 
@@ -211,7 +224,7 @@
 int virtqueue_gather_used(virtqueue_driver_t *vq, virtqueue_ring_object_t *robj,
                           void **buf, unsigned *len, vq_flags_t *flag)
 {
-    if (robj->cur == DESC_TABLE_SIZE) {
+    if (robj->cur >= vq->queue_len) {
         return 0;
     }
     robj->cur = vq_pop_desc(vq, robj->cur, buf, len, flag);