The existing sandbox implementation of virtio only tests the basic API.
It is not able to provide a block device, for example.
Add a new implementation which operations at a higher level. It makes
use of the existing MMIO driver to perform virtio operations.
This emulator-device should be the parent of a function-specific
emulator. That emulator uses this MMIO transport to communicate with the
controller:
virtio-blk {
compatible = "sandbox,virtio-blk-emul";
mmio {
compatible = "sandbox,virtio-emul";
};
};
A new UCLASS_VIRTIO_EMUL uclass is created for the child devices, which
implement the actual function (block device, random-number generator,
etc.)
Signed-off-by: Simon Glass <sjg@chromium.org>
111 lines
2.9 KiB
C
111 lines
2.9 KiB
C
/* SPDX-License-Identifier: GPL-2.0+ */
|
|
/*
|
|
* VirtIO Sandbox emulator, for testing purpose only. This emulates the QEMU
|
|
* side of virtio, using the MMIO driver and handling any accesses
|
|
*
|
|
* This handles traffic from the virtio_ring
|
|
*
|
|
* Copyright 2025 Simon Glass <sjg@chromium.org>
|
|
*/
|
|
|
|
#ifndef __SANDBOX_EMUL_H
|
|
#define __SANDBOX_EMUL_H
|
|
|
|
#include "virtio_mmio.h"
|
|
#include "virtio_types.h"
|
|
|
|
enum sandboxio_size_t;
|
|
struct udevice;
|
|
struct vring_desc;
|
|
|
|
enum {
|
|
MAX_VIRTIO_QUEUES = 8,
|
|
QUEUE_MAX_SIZE = 256,
|
|
};
|
|
|
|
/**
|
|
* struct virtio_emul_queue - Emulator's state for a single virtqueue
|
|
*/
|
|
struct virtio_emul_queue {
|
|
__virtio32 num;
|
|
__virtio32 ready;
|
|
__virtio64 desc_addr;
|
|
__virtio64 avail_addr;
|
|
__virtio64 used_addr;
|
|
__virtio16 last_avail_idx; // Device's internal counter
|
|
};
|
|
|
|
/**
|
|
* struct sandbox_emul_priv - Private info for the emulator
|
|
*/
|
|
struct sandbox_emul_priv {
|
|
struct virtio_mmio_priv mmio;
|
|
int num_queues;
|
|
int queue_sel;
|
|
u32 status;
|
|
u64 features_sel;
|
|
u64 features;
|
|
u64 driver_features;
|
|
u32 interrupt_status;
|
|
u32 config_generation;
|
|
struct virtio_emul_queue queues[MAX_VIRTIO_QUEUES];
|
|
};
|
|
|
|
/**
|
|
* struct virtio_emul_ops - Operations for a virtio device emulator
|
|
*
|
|
* @process_request:
|
|
* @get_config: Reads from the device-specific configuration space
|
|
* @get_features: Returns the device-specific feature bits
|
|
*/
|
|
struct virtio_emul_ops {
|
|
/**
|
|
* process_request() - Handles a single request from the driver
|
|
*
|
|
* @dev: The emulator device
|
|
* @descs: Pointer to the virtqueue's descriptor table
|
|
* @head_idx: The index of the first descriptor in the chain for
|
|
* this request
|
|
* @writtenp: Returns the total number of bytes written by the
|
|
* device into the driver's buffers (e.g. for a read
|
|
* request and the status byte). This is what will be
|
|
* placed in the `len` field of the used ring element.
|
|
* @return 0 on success, negative on error.
|
|
*/
|
|
int (*process_request)(struct udevice *dev, struct vring_desc *descs,
|
|
u32 head_idx, int *writtenp);
|
|
|
|
/**
|
|
* get_config() - Reads from the device-specific configuration space
|
|
*
|
|
* @dev: The emulator device
|
|
* @offset: The byte offset into the configuration space to read from
|
|
* @buf: The buffer to copy the configuration data into
|
|
* @size: The number of bytes to read
|
|
* @return 0 on success, negative on error.
|
|
*/
|
|
int (*get_config)(struct udevice *dev, ulong offset, void *buf,
|
|
enum sandboxio_size_t size);
|
|
|
|
/**
|
|
* get_features() - Returns the device-specific feature bits
|
|
*
|
|
* @dev: The emulator device
|
|
* @return A bitmask of the device-specific features to be OR'd
|
|
* with the transport features.
|
|
*/
|
|
u64 (*get_features)(struct udevice *dev);
|
|
|
|
/**
|
|
* get_device_id() - Returns the virtio device ID
|
|
*
|
|
* @dev: The emulator device
|
|
* @return The virtio device ID for this emulator
|
|
*/
|
|
u32 (*get_device_id)(struct udevice *dev);
|
|
};
|
|
|
|
#define virtio_emul_get_ops(dev) ((struct virtio_emul_ops *)(dev)->driver->ops)
|
|
|
|
#endif
|