VirtIO library (libvirtio)#
libvirtio
provides an abstraction layer for working with VirtIO
devices. VirtIO
is a standard dedicated to provide
a common device API (e.g. network and mass storage adapters) for virtualized execution environment.
Contents#
General information#
The library offers a set of functionalities for VirtIO
device initialization, configuration, data exchange, and
cleanup. It supports both legacy and modern VirtIO
device models, offering compatibility with various device types
including network (virtio-net) and block devices (virtio-blk). The library uses condition variables and mutexes
(handle_t) to ensure thread-safe interactions with VirtIO
devices and queues.
libvirtio interface#
Device and Queue Management#
virtio_initDev
- Initializes aVirtIO
device.
int virtio_initDev(virtio_dev_t *vdev)
virtio_destroyDev
- Cleans up resources associated with aVirtIO
device.
void virtio_destroyDev(virtio_dev_t *vdev)
virtqueue_init
- Initializes aVirtIO
queue.
int virtqueue_init(virtio_dev_t *vdev, virtqueue_t *vq, unsigned int idx, unsigned int size)
virtqueue_destroy
- Cleans up resources associated with aVirtIO
queue.
void virtqueue_destroy(virtio_dev_t *vdev, virtqueue_t *vq)
Data Exchange#
virtqueue_enqueue
- Enqueues a request in aVirtIO
queue for processing by the device.
int virtqueue_enqueue(virtio_dev_t *vdev, virtqueue_t *vq, virtio_req_t *req)
virtqueue_dequeue
- Dequeues a processed request from aVirtIO
queue.
void *virtqueue_dequeue(virtio_dev_t *vdev, virtqueue_t *vq, unsigned int *len)
virtqueue_notify
- Notifies the device that there are available requests in the queue.
void virtqueue_notify(virtio_dev_t *vdev, virtqueue_t *vq)
virtqueue_enableIRQ
- Enable interrupts for aVirtIO
queue.
void virtqueue_enableIRQ(virtio_dev_t *vdev, virtqueue_t *vq)
virtqueue_disableIRQ
- Disable interrupts for aVirtIO
queue.
void virtqueue_disableIRQ(virtio_dev_t *vdev, virtqueue_t *vq)
Configuration and Status#
virtio_readConfig
- Read from theVirtIO
device’s configuration space.
uint8_t virtio_readConfig8(virtio_dev_t *vdev, unsigned int reg);
uint16_t virtio_readConfig16(virtio_dev_t *vdev, unsigned int reg);
uint32_t virtio_readConfig32(virtio_dev_t *vdev, unsigned int reg);
uint64_t virtio_readConfig64(virtio_dev_t *vdev, unsigned int reg);
virtio_writeConfig
-Write to theVirtIO
device’s configuration space.
void virtio_writeConfig8(virtio_dev_t *vdev, unsigned int reg, uint8_t val);
void virtio_writeConfig16(virtio_dev_t *vdev, unsigned int reg, uint16_t val);
void virtio_writeConfig32(virtio_dev_t *vdev, unsigned int reg, uint32_t val);
void virtio_writeConfig64(virtio_dev_t *vdev, unsigned int reg, uint64_t val);
virtio_readFeatures
- ReadVirtIO
device features.
uint64_t virtio_readFeatures(virtio_dev_t *vdev)
virtio_writeFeatures
- WriteVirtIO
device features.
int virtio_writeFeatures(virtio_dev_t *vdev, uint64_t features)
virtio_readStatus
- Read theVirtIO
device status register.
uint8_t virtio_readStatus(virtio_dev_t *vdev)
virtio_writeStatus
- Write theVirtIO
device status register.
void virtio_writeStatus(virtio_dev_t *vdev, uint8_t status)
virtio_isr
- Reads the interrupt status.
unsigned int virtio_isr(virtio_dev_t *vdev)
Utility#
virtio_reset
- Resets aVirtIO
device to its initial state.
void virtio_reset(virtio_dev_t *vdev)
virtio_find
- Detects the nextVirtIO
device matching a given device descriptor.
int virtio_find(const virtio_devinfo_t *info, virtio_dev_t *vdev, virtio_ctx_t *vctx)
virtio_init
- Initialize theVirtIO
library.
int virtio_init(void)
virtio_done
- Clean up theVirtIO
library.
int virtio_done(void)
Memory Barriers#
virtio_mb
- Provides a memory barrier to ensure memory operations’ ordering.
void virtio_mb(void)
Data Structures#
virtio_devtype_t
- Enumerates the types ofVirtIO
devices, such as PCI and MMIO devices.
typedef enum {
vdevNONE = 0x00, /* No VirtIO device */
vdevPCI = 0x01, /* VirtIO PCI device */
vdevMMIO = 0x02 /* VirtIO MMIO device */
} virtio_devtype_t;
virtio_seg_t
- Represents a segment of a data buffer for I/O operations, forming a doubly linked list.
struct _virtio_seg_t {
void *buff; /* Buffer exposed to device */
unsigned int len; /* Buffer length */
virtio_seg_t *prev, *next; /* Doubly linked list */
};
virtio_req_t
- Encapsulates a request to be processed by aVirtIO
device, comprising a list of segments.
typedef struct {
virtio_seg_t *segs; /* Request segments list */
unsigned int rsegs; /* Number of device readable segments */
unsigned int wsegs; /* Number of device writable segments */
} virtio_req_t;
virtio_desc_t
- Represents a descriptor in theVirtIO
queue.
typedef struct {
uint64_t addr; /* Buffer physical address */
uint32_t len; /* Buffer length */
uint16_t flags; /* Descriptor flags */
uint16_t next; /* Next chained descriptor index (if flags & 0x1) */
} __attribute__((packed)) virtio_desc_t;
virtio_avail_t
/virtio_used_t
- Structures used to manage available and used rings in aVirtIO
queue.
typedef struct {
uint16_t flags; /* Used buffer notification suppression */
uint16_t idx; /* Next available request index */
uint16_t ring[]; /* Available requests (descriptor chain IDs) */
} __attribute__((packed)) virtio_avail_t;
typedef struct {
uint16_t flags; /* Available buffer notification suppression */
uint16_t idx; /* Next processed request ring index */
virtio_used_elem_t ring[]; /* Processed requests */
} __attribute__((packed)) virtio_used_t;
virtqueue_t
- Represents aVirtIO
queue, holding the queue’s descriptors, available and used rings, and synchronization primitives.
typedef struct {
/* Standard split virtqueue layout */
volatile virtio_desc_t *desc; /* Descriptors */
volatile virtio_avail_t *avail; /* Avail ring */
volatile uint16_t *uevent; /* Used event notification suppression */
volatile virtio_used_t *used; /* Used ring */
volatile uint16_t *aevent; /* Avail event notification suppression */
/* Custom helper fields */
void **buffs; /* Descriptors buffers */
void *mem; /* Allocated virtqueue memory */
unsigned int memsz; /* Allocated virtqueue memory size */
unsigned int idx; /* Virtqueue index */
unsigned int size; /* Virtqueue size */
unsigned int noffs; /* Virtqueue notification area offset (modern VirtIO PCI device only) */
unsigned int nfree; /* Number of free descriptors */
uint16_t free; /* Next free descriptor index */
uint16_t last; /* Last processed request index */
/* Synchronization */
handle_t cond; /* Free descriptors condition variable */
handle_t lock; /* Virtqueue mutex */
} virtqueue_t;
virtio_devinfo_t
- Contains basic information about a VirtIO device, including its type, ID, and register addresses.
typedef struct {
virtio_devtype_t type; /* VirtIO device type */
unsigned int id; /* VirtIO device ID */
unsigned int irq; /* Interrupt number */
unsigned int xntf; /* Notification registers offset multiplier */
virtio_reg_t base; /* Base registers */
virtio_reg_t ntf; /* Notification register */
virtio_reg_t isr; /* Interrupt status register */
virtio_reg_t cfg; /* Configuration registers */
} virtio_devinfo_t;
virtio_dev_t
- Encapsulates a VirtIO device, including its features and device-specific information.
typedef struct {
virtio_devinfo_t info; /* VirtIO device core data */
uint64_t features; /* VirtIO device features */
} virtio_dev_t;
virtio_ctx_t
- Used for device detection and context management.
typedef struct {
unsigned char reset; /* Indicates that context to be reset */
unsigned char ctx[32]; /* VirtIO device detection context */
} virtio_ctx_t;
Using libvirtio#
To use functions provided by libvirtio
please add the library to the LIBS
variable in Makefile
and include the
required header file.
Running tests#
VirtIO
library provides the basic set of tests, which is available in
phoenix-rtos-tests.