From 274524da02c176bb93c3d1e033c0eee7373daebe Mon Sep 17 00:00:00 2001 From: agicy Date: Wed, 12 Aug 2026 02:56:57 +0000 Subject: [PATCH 1/6] refactor(virtio): introduce device ops table and per-device entries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add struct virtio_device_ops (type/features/num_queues/queue_max_size/ init/close/reset/status_changed/notify_handlers) in virtio.h, and one const ops instance per device defined in its own .c, together with the typed init params structs and do_init wrappers that unpack them. Purely additive — the table is consumed in the following commit. --- tools/virtio/devices/blk/virtio_blk.c | 30 ++++- tools/virtio/devices/console/virtio_console.c | 27 ++++- tools/virtio/devices/gpu/virtio_gpu_base.c | 105 ++++++++++------- tools/virtio/devices/net/virtio_net.c | 33 ++++++ tools/virtio/devices/scmi/virtio_scmi.c | 109 ++++++++++++++++-- tools/virtio/include/virtio.h | 13 +++ tools/virtio/include/virtio_blk.h | 7 ++ tools/virtio/include/virtio_console.h | 4 + tools/virtio/include/virtio_gpu.h | 4 +- tools/virtio/include/virtio_net.h | 9 ++ tools/virtio/include/virtio_scmi.h | 22 +++- 11 files changed, 309 insertions(+), 54 deletions(-) diff --git a/tools/virtio/devices/blk/virtio_blk.c b/tools/virtio/devices/blk/virtio_blk.c index 76b8d55e..a201975d 100644 --- a/tools/virtio/devices/blk/virtio_blk.c +++ b/tools/virtio/devices/blk/virtio_blk.c @@ -252,6 +252,12 @@ int virtio_blk_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { return 0; } +void virtio_blk_reset(VirtIODevice *vdev) { (void)vdev; } + +/* + * Shut down the blk device: signal close, wait for the worker to exit, + * then release all resources. + */ void virtio_blk_close(VirtIODevice *vdev) { BlkDev *dev = vdev->dev; pthread_mutex_lock(&dev->mtx); @@ -265,4 +271,26 @@ void virtio_blk_close(VirtIODevice *vdev) { free(dev); free(vdev->vqs); free(vdev); -} \ No newline at end of file +} + +static int virtio_blk_do_init(VirtIODevice *vdev, void *params) { + const struct virtio_blk_init_params *p = params; + if (!p) + return -EINVAL; + if (!init_blk_dev(vdev)) + return -ENOMEM; + if (virtio_blk_init(vdev, p->img_path) != 0) + return -EIO; + return 0; +} + +const struct virtio_device_ops virtio_blk_ops = { + .type = VirtioTBlock, + .features = BLK_SUPPORTED_FEATURES, + .num_queues = 1, + .queue_max_size = VIRTQUEUE_BLK_MAX_SIZE, + .init = virtio_blk_do_init, + .close = virtio_blk_close, + .reset = virtio_blk_reset, + .notify_handlers = {virtio_blk_notify_handler}, +}; diff --git a/tools/virtio/devices/console/virtio_console.c b/tools/virtio/devices/console/virtio_console.c index 240ddbfb..42970348 100644 --- a/tools/virtio/devices/console/virtio_console.c +++ b/tools/virtio/devices/console/virtio_console.c @@ -204,6 +204,8 @@ int virtio_console_txq_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { return 0; } +void virtio_console_reset(VirtIODevice *vdev) { (void)vdev; } + void virtio_console_close(VirtIODevice *vdev) { ConsoleDev *dev = vdev->dev; close(dev->master_fd); @@ -214,4 +216,27 @@ void virtio_console_close(VirtIODevice *vdev) { free(dev); free(vdev->vqs); free(vdev); -} \ No newline at end of file +} + +static int virtio_console_do_init(VirtIODevice *vdev, void *params) { + (void)params; + vdev->dev = init_console_dev(); + if (!vdev->dev) + return -ENOMEM; + return virtio_console_init(vdev); +} + +const struct virtio_device_ops virtio_console_ops = { + .type = VirtioTConsole, + .features = CONSOLE_SUPPORTED_FEATURES, + .num_queues = CONSOLE_MAX_QUEUES, + .queue_max_size = VIRTQUEUE_CONSOLE_MAX_SIZE, + .init = virtio_console_do_init, + .close = virtio_console_close, + .reset = virtio_console_reset, + .notify_handlers = + { + [CONSOLE_QUEUE_RX] = virtio_console_rxq_notify_handler, + [CONSOLE_QUEUE_TX] = virtio_console_txq_notify_handler, + }, +}; \ No newline at end of file diff --git a/tools/virtio/devices/gpu/virtio_gpu_base.c b/tools/virtio/devices/gpu/virtio_gpu_base.c index d727ccd6..8e4cad20 100644 --- a/tools/virtio/devices/gpu/virtio_gpu_base.c +++ b/tools/virtio/devices/gpu/virtio_gpu_base.c @@ -13,6 +13,7 @@ #include "unistd.h" #include "virtio.h" #include "virtio_gpu.h" +#include #include #include #include @@ -96,9 +97,6 @@ int virtio_gpu_init(VirtIODevice *vdev) { // TODO: Display device initialization GPUDev *gdev = vdev->dev; - // Set the close function for virtio gpu - vdev->virtio_close = virtio_gpu_close; - int drm_fd = 0; // Open card0 @@ -185,57 +183,64 @@ int virtio_gpu_init(VirtIODevice *vdev) { } void virtio_gpu_close(VirtIODevice *vdev) { + if (!vdev) + return; + log_info("virtio_gpu close"); - // Reclaim memory related to scanouts - GPUDev *gdev = (GPUDev *)vdev->dev; - for (int i = 0; i < gdev->scanouts_num; ++i) { - free(gdev->scanouts[i].current_cursor); + GPUDev *gdev = vdev->dev; + if (gdev) { + // Reclaim memory related to scanouts + for (int i = 0; i < gdev->scanouts_num; ++i) { + free(gdev->scanouts[i].current_cursor); - virtio_gpu_remove_drm_framebuffer(&gdev->scanouts[i]); + virtio_gpu_remove_drm_framebuffer(&gdev->scanouts[i]); - drmModeFreeCrtc(gdev->scanouts[i].crtc); - drmModeFreeEncoder(gdev->scanouts[i].encoder); - drmModeFreeConnector(gdev->scanouts[i].connector); + drmModeFreeCrtc(gdev->scanouts[i].crtc); + drmModeFreeEncoder(gdev->scanouts[i].encoder); + drmModeFreeConnector(gdev->scanouts[i].connector); - // Release card0_fd - if (gdev->scanouts[i].card0_fd != -1) { - close(gdev->scanouts[i].card0_fd); + if (gdev->scanouts[i].card0_fd != -1) { + close(gdev->scanouts[i].card0_fd); + } } - } - // Reclaim memory related to resources - while (!TAILQ_EMPTY(&gdev->resource_list)) { - GPUSimpleResource *temp = TAILQ_FIRST(&gdev->resource_list); - TAILQ_REMOVE(&gdev->resource_list, temp, next); - free(temp); - } + // Reclaim memory related to resources + while (!TAILQ_EMPTY(&gdev->resource_list)) { + GPUSimpleResource *temp = TAILQ_FIRST(&gdev->resource_list); + TAILQ_REMOVE(&gdev->resource_list, temp, next); + free(temp); + } - // Reclaim memory related to command queue - while (!TAILQ_EMPTY(&gdev->command_queue)) { - GPUCommand *temp = TAILQ_FIRST(&gdev->command_queue); - TAILQ_REMOVE(&gdev->command_queue, temp, next); - free(temp); - } + // Reclaim memory related to command queue + while (!TAILQ_EMPTY(&gdev->command_queue)) { + GPUCommand *temp = TAILQ_FIRST(&gdev->command_queue); + TAILQ_REMOVE(&gdev->command_queue, temp, next); + free(temp); + } - // Reclaim async part - gdev->close = true; - pthread_cond_signal(&gdev->gpu_cond); - pthread_join(gdev->gpu_thread, NULL); - pthread_cond_destroy(&gdev->gpu_cond); - pthread_mutex_destroy(&gdev->queue_mutex); + // Reclaim async part + gdev->close = true; + pthread_cond_signal(&gdev->gpu_cond); + pthread_join(gdev->gpu_thread, NULL); + pthread_cond_destroy(&gdev->gpu_cond); + pthread_mutex_destroy(&gdev->queue_mutex); - free(gdev); - gdev = NULL; + free(gdev); + vdev->dev = NULL; + } - // vq is managed by the driver frontend, free it directly here free(vdev->vqs); + vdev->vqs = NULL; free(vdev); } -void virtio_gpu_reset(GPUDev *gdev) { - // TODO: - for (int i = 0; i < HVISOR_VIRTIO_GPU_MAX_SCANOUTS; ++i) { +void virtio_gpu_reset(VirtIODevice *vdev) { + if (!vdev || !vdev->dev) + return; + + GPUDev *gdev = vdev->dev; + for (int i = 0; i < gdev->scanouts_num; ++i) { gdev->scanouts[i].resource_id = 0; gdev->scanouts[i].width = 0; gdev->scanouts[i].height = 0; @@ -244,6 +249,28 @@ void virtio_gpu_reset(GPUDev *gdev) { } } +static int virtio_gpu_do_init(VirtIODevice *vdev, void *params) { + vdev->dev = init_gpu_dev(params); + if (!vdev->dev) + return -ENOMEM; + return virtio_gpu_init(vdev); +} + +const struct virtio_device_ops virtio_gpu_ops = { + .type = VirtioTGPU, + .features = GPU_SUPPORTED_FEATURES, + .num_queues = GPU_MAX_QUEUES, + .queue_max_size = VIRTQUEUE_GPU_MAX_SIZE, + .init = virtio_gpu_do_init, + .close = virtio_gpu_close, + .reset = virtio_gpu_reset, + .notify_handlers = + { + [GPU_CONTROL_QUEUE] = virtio_gpu_ctrl_notify_handler, + [GPU_CURSOR_QUEUE] = virtio_gpu_cursor_notify_handler, + }, +}; + int virtio_gpu_ctrl_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { log_debug("entering %s", __func__); diff --git a/tools/virtio/devices/net/virtio_net.c b/tools/virtio/devices/net/virtio_net.c index 4bccd250..2eb8b2e3 100644 --- a/tools/virtio/devices/net/virtio_net.c +++ b/tools/virtio/devices/net/virtio_net.c @@ -320,6 +320,13 @@ int virtio_net_init(VirtIODevice *vdev, char *devname) { return 0; } +void virtio_net_reset(VirtIODevice *vdev) { + if (!vdev || !vdev->dev) + return; + NetDev *dev = vdev->dev; + dev->rx_ready = false; +} + void virtio_net_close(VirtIODevice *vdev) { NetDev *dev = vdev->dev; close(dev->tapfd); @@ -330,3 +337,29 @@ void virtio_net_close(VirtIODevice *vdev) { free(vdev->vqs); free(vdev); } + +static int virtio_net_do_init(VirtIODevice *vdev, void *params) { + const struct virtio_net_init_params *p = params; + if (!p) + return -EINVAL; + vdev->dev = init_net_dev((uint8_t *)p->mac); + if (!vdev->dev) + return -ENOMEM; + return virtio_net_init(vdev, (char *)p->tap); +} + +const struct virtio_device_ops virtio_net_ops = { + .type = VirtioTNet, + .features = NET_SUPPORTED_FEATURES, + .num_queues = NET_MAX_QUEUES, + .queue_max_size = VIRTQUEUE_NET_MAX_SIZE, + .init = virtio_net_do_init, + .close = virtio_net_close, + .reset = virtio_net_reset, + .status_changed = net_on_status, + .notify_handlers = + { + [NET_QUEUE_RX] = virtio_net_rxq_notify_handler, + [NET_QUEUE_TX] = virtio_net_txq_notify_handler, + }, +}; diff --git a/tools/virtio/devices/scmi/virtio_scmi.c b/tools/virtio/devices/scmi/virtio_scmi.c index 8a2f0e31..9f7b9d7e 100644 --- a/tools/virtio/devices/scmi/virtio_scmi.c +++ b/tools/virtio/devices/scmi/virtio_scmi.c @@ -65,19 +65,28 @@ void scmi_dev_free(SCMIDev *dev) { free(dev); } -int scmi_dev_parse_clock_ids(SCMIDev *dev, void *json_array) { - return parse_id_array((cJSON *)json_array, &dev->clock_ids, - &dev->clock_count); +int scmi_dev_parse_clock_ids(struct virtio_scmi_init_params *p, + void *json_array) { + return parse_id_array((cJSON *)json_array, &p->clock_ids, &p->clock_count); } -int scmi_dev_parse_reset_ids(SCMIDev *dev, void *json_array) { - return parse_id_array((cJSON *)json_array, &dev->reset_ids, - &dev->reset_count); +int scmi_dev_parse_reset_ids(struct virtio_scmi_init_params *p, + void *json_array) { + return parse_id_array((cJSON *)json_array, &p->reset_ids, &p->reset_count); } -int scmi_dev_parse_power_ids(SCMIDev *dev, void *json_array) { - return parse_id_array((cJSON *)json_array, &dev->power_ids, - &dev->power_count); +int scmi_dev_parse_power_ids(struct virtio_scmi_init_params *p, + void *json_array) { + return parse_id_array((cJSON *)json_array, &p->power_ids, &p->power_count); +} + +void scmi_dev_free_params(struct virtio_scmi_init_params *p) { + if (!p) + return; + free(p->clock_ids); + free(p->reset_ids); + free(p->power_ids); + free(p); } static int virtq_tx_handle_one_request(void *dev, VirtQueue *vq) { @@ -168,9 +177,91 @@ int virtio_scmi_txq_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { return 0; } +void virtio_scmi_reset(VirtIODevice *vdev) { (void)vdev; } + void virtio_scmi_close(VirtIODevice *vdev) { SCMIDev *dev = vdev->dev; scmi_dev_free(dev); free(vdev->vqs); free(vdev); } + +static int virtio_scmi_do_init(VirtIODevice *vdev, void *params) { + const struct virtio_scmi_init_params *p = params; + SCMIDev *dev; + + if (p) { + dev = calloc(1, sizeof(SCMIDev)); + if (!dev) + return -ENOMEM; + + // Deep-copy id arrays so that SCMIDev and the caller each own their + // copies — no ownership transfer, no double-free risk. + if (p->clock_count > 0) { + dev->clock_ids = calloc(p->clock_count, sizeof(uint32_t)); + if (!dev->clock_ids) + goto err_copy; + memcpy(dev->clock_ids, p->clock_ids, + p->clock_count * sizeof(uint32_t)); + } + dev->clock_count = p->clock_count; + + if (p->reset_count > 0) { + dev->reset_ids = calloc(p->reset_count, sizeof(uint32_t)); + if (!dev->reset_ids) + goto err_copy; + memcpy(dev->reset_ids, p->reset_ids, + p->reset_count * sizeof(uint32_t)); + } + dev->reset_count = p->reset_count; + + if (p->power_count > 0) { + dev->power_ids = calloc(p->power_count, sizeof(uint32_t)); + if (!dev->power_ids) + goto err_copy; + memcpy(dev->power_ids, p->power_ids, + p->power_count * sizeof(uint32_t)); + } + dev->power_count = p->power_count; + + scmi_dev_register_protocol(dev, SCMI_PROTO_ID_BASE, + virtio_scmi_base_handle_req); + if (dev->clock_count > 0) + scmi_dev_register_protocol(dev, SCMI_PROTO_ID_CLOCK, + virtio_scmi_clock_handle_req); + if (dev->power_count > 0) + scmi_dev_register_protocol(dev, SCMI_PROTO_ID_POWER, + virtio_scmi_power_handle_req); + if (dev->reset_count > 0) + scmi_dev_register_protocol(dev, SCMI_PROTO_ID_RESET, + virtio_scmi_reset_handle_req); + } else { + dev = scmi_dev_create(); + if (!dev) + return -ENOMEM; + } + + vdev->dev = dev; + return 0; + +err_copy: + free(dev->clock_ids); + free(dev->reset_ids); + free(dev->power_ids); + free(dev); + return -ENOMEM; +} + +const struct virtio_device_ops virtio_scmi_ops = { + .type = VirtioTSCMI, + .features = SCMI_SUPPORTED_FEATURES, + .num_queues = SCMI_MAX_QUEUES, + .queue_max_size = VIRTQUEUE_SCMI_MAX_SIZE, + .init = virtio_scmi_do_init, + .close = virtio_scmi_close, + .reset = virtio_scmi_reset, + .notify_handlers = + { + [SCMI_QUEUE_TX] = virtio_scmi_txq_notify_handler, + }, +}; diff --git a/tools/virtio/include/virtio.h b/tools/virtio/include/virtio.h index 5dd92615..4c73b978 100644 --- a/tools/virtio/include/virtio.h +++ b/tools/virtio/include/virtio.h @@ -131,6 +131,19 @@ struct VirtIODevice { bool interrupt_line_asserted; }; +struct virtio_device_ops { + VirtioDeviceType type; + uint64_t features; + uint32_t num_queues; + uint32_t queue_max_size; + int (*init)(VirtIODevice *vdev, void *params); + void (*close)(VirtIODevice *vdev); + void (*reset)(VirtIODevice *vdev); + void (*status_changed)(VirtIODevice *vdev, uint32_t status); +#define VIRTIO_MAX_VQUEUES 4 + int (*notify_handlers[VIRTIO_MAX_VQUEUES])(VirtIODevice *, VirtQueue *); +}; + // used event idx for driver telling device when to notify driver. #define VQ_USED_EVENT(vq) ((vq)->avail_ring->ring[(vq)->num]) // avail event idx for device telling driver when to notify device. diff --git a/tools/virtio/include/virtio_blk.h b/tools/virtio/include/virtio_blk.h index 17a3a722..34754f79 100644 --- a/tools/virtio/include/virtio_blk.h +++ b/tools/virtio/include/virtio_blk.h @@ -52,9 +52,16 @@ typedef struct virtio_blk_dev { int close; } BlkDev; +struct virtio_blk_init_params { + const char *img_path; +}; + BlkDev *init_blk_dev(VirtIODevice *vdev); int virtio_blk_init(VirtIODevice *vdev, const char *img_path); int virtio_blk_notify_handler(VirtIODevice *vdev, VirtQueue *vq); void virtio_blk_close(VirtIODevice *vdev); +void virtio_blk_reset(VirtIODevice *vdev); + +extern const struct virtio_device_ops virtio_blk_ops; #endif /* _HVISOR_VIRTIO_BLK_H */ diff --git a/tools/virtio/include/virtio_console.h b/tools/virtio/include/virtio_console.h index bd08ebd1..eacdaa9d 100644 --- a/tools/virtio/include/virtio_console.h +++ b/tools/virtio/include/virtio_console.h @@ -35,4 +35,8 @@ int virtio_console_init(VirtIODevice *vdev); int virtio_console_rxq_notify_handler(VirtIODevice *vdev, VirtQueue *vq); int virtio_console_txq_notify_handler(VirtIODevice *vdev, VirtQueue *vq); void virtio_console_close(VirtIODevice *vdev); +void virtio_console_reset(VirtIODevice *vdev); + +extern const struct virtio_device_ops virtio_console_ops; + #endif \ No newline at end of file diff --git a/tools/virtio/include/virtio_gpu.h b/tools/virtio/include/virtio_gpu.h index f3de4c14..9f1d5282 100644 --- a/tools/virtio/include/virtio_gpu.h +++ b/tools/virtio/include/virtio_gpu.h @@ -221,7 +221,9 @@ int virtio_gpu_init(VirtIODevice *vdev); void virtio_gpu_close(VirtIODevice *vdev); // Reset virtio-gpu device -void virtio_gpu_reset(); +void virtio_gpu_reset(VirtIODevice *vdev); + +extern const struct virtio_device_ops virtio_gpu_ops; // Handler function when controlq has requests to process int virtio_gpu_ctrl_notify_handler(VirtIODevice *vdev, VirtQueue *vq); diff --git a/tools/virtio/include/virtio_net.h b/tools/virtio/include/virtio_net.h index 0f457a09..79934963 100644 --- a/tools/virtio/include/virtio_net.h +++ b/tools/virtio/include/virtio_net.h @@ -23,6 +23,11 @@ #define VIRTQUEUE_NET_MAX_SIZE 256 +struct virtio_net_init_params { + const uint8_t *mac; + const char *tap; +}; + // Max iov entries for a single descriptor chain. Each descriptor in the // chain contributes at most one iov entry, and a chain can never exceed // the total queue size (a single descriptor's next field cannot wrap past @@ -56,5 +61,9 @@ int virtio_net_txq_notify_handler(VirtIODevice *vdev, VirtQueue *vq); void virtio_net_event_handler(int fd, int epoll_type, void *param); int virtio_net_init(VirtIODevice *vdev, char *devname); void virtio_net_close(VirtIODevice *vdev); +void virtio_net_reset(VirtIODevice *vdev); void net_on_status(VirtIODevice *vdev, uint32_t status); + +extern const struct virtio_device_ops virtio_net_ops; + #endif //_HVISOR_VIRTIO_NET_H diff --git a/tools/virtio/include/virtio_scmi.h b/tools/virtio/include/virtio_scmi.h index 0c63926c..4180b2ca 100644 --- a/tools/virtio/include/virtio_scmi.h +++ b/tools/virtio/include/virtio_scmi.h @@ -235,15 +235,31 @@ int scmi_handle_message(SCMIDev *dev, uint8_t protocol_id, uint8_t msg_id, uint16_t token, const struct iovec *req_iov, struct scmi_resp_ctx *ctx); +struct virtio_scmi_init_params { + uint32_t *clock_ids; + uint32_t clock_count; + uint32_t *reset_ids; + uint32_t reset_count; + uint32_t *power_ids; + uint32_t power_count; +}; + SCMIDev *scmi_dev_create(void); void scmi_dev_free(SCMIDev *dev); int virtio_scmi_txq_notify_handler(VirtIODevice *vdev, VirtQueue *vq); void virtio_scmi_close(VirtIODevice *vdev); +void virtio_scmi_reset(VirtIODevice *vdev); + +extern const struct virtio_device_ops virtio_scmi_ops; /* JSON array parsing: fills dev->clock_ids / dev->reset_ids / dev->power_ids */ -int scmi_dev_parse_clock_ids(SCMIDev *dev, void *json_array); -int scmi_dev_parse_reset_ids(SCMIDev *dev, void *json_array); -int scmi_dev_parse_power_ids(SCMIDev *dev, void *json_array); +int scmi_dev_parse_clock_ids(struct virtio_scmi_init_params *p, + void *json_array); +int scmi_dev_parse_reset_ids(struct virtio_scmi_init_params *p, + void *json_array); +int scmi_dev_parse_power_ids(struct virtio_scmi_init_params *p, + void *json_array); +void scmi_dev_free_params(struct virtio_scmi_init_params *p); /* /dev/hvisor fd, opened once in virtio_start() */ extern int ko_fd; From fcab9c057933d6731fa06081d81473d1991c3732 Mon Sep 17 00:00:00 2001 From: agicy Date: Wed, 12 Aug 2026 02:56:57 +0000 Subject: [PATCH 2/6] refactor(virtio): drive device creation from the ops table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the switch-cases in create_virtio_device and init_virtio_queue with table lookups: features, queue count/size and per-queue notify handlers now come from the device's ops entry, init goes through ops->init with params, and the error path tears down via ops->close instead of a bare free(). The queue setup loop is table-driven too (ops->num_queues / queue_max_size / notify_handlers). Drop the now-redundant manual vdev->virtio_close / status_changed assignments in device inits — the table wires them up centrally. --- tools/virtio/devices/blk/virtio_blk.c | 1 - tools/virtio/devices/console/virtio_console.c | 1 - tools/virtio/devices/net/virtio_net.c | 2 - tools/virtio/include/virtio.h | 4 +- tools/virtio/virtio.c | 293 +++++++----------- 5 files changed, 111 insertions(+), 190 deletions(-) diff --git a/tools/virtio/devices/blk/virtio_blk.c b/tools/virtio/devices/blk/virtio_blk.c index a201975d..71062f10 100644 --- a/tools/virtio/devices/blk/virtio_blk.c +++ b/tools/virtio/devices/blk/virtio_blk.c @@ -164,7 +164,6 @@ int virtio_blk_init(VirtIODevice *vdev, const char *img_path) { dev->config.capacity = blk_size; dev->config.size_max = blk_size; dev->img_fd = img_fd; - vdev->virtio_close = virtio_blk_close; log_info("debug: virtio_blk_init: %s, size is %lld", img_path, dev->config.capacity); return 0; diff --git a/tools/virtio/devices/console/virtio_console.c b/tools/virtio/devices/console/virtio_console.c index 42970348..a2515971 100644 --- a/tools/virtio/devices/console/virtio_console.c +++ b/tools/virtio/devices/console/virtio_console.c @@ -153,7 +153,6 @@ int virtio_console_init(VirtIODevice *vdev) { return -1; } - vdev->virtio_close = virtio_console_close; return 0; } diff --git a/tools/virtio/devices/net/virtio_net.c b/tools/virtio/devices/net/virtio_net.c index 2eb8b2e3..7f0e2dcb 100644 --- a/tools/virtio/devices/net/virtio_net.c +++ b/tools/virtio/devices/net/virtio_net.c @@ -315,8 +315,6 @@ int virtio_net_init(VirtIODevice *vdev, char *devname) { net->tapfd = -1; return -1; } - vdev->status_changed = net_on_status; - vdev->virtio_close = virtio_net_close; return 0; } diff --git a/tools/virtio/include/virtio.h b/tools/virtio/include/virtio.h index 4c73b978..83c736ed 100644 --- a/tools/virtio/include/virtio.h +++ b/tools/virtio/include/virtio.h @@ -169,9 +169,7 @@ void rw_barrier(void); VirtIODevice *create_virtio_device(VirtioDeviceType dev_type, uint32_t zone_id, uint64_t base_addr, uint64_t len, - uint32_t irq_id, void *arg0, void *arg1); - -void init_virtio_queue(VirtIODevice *vdev, VirtioDeviceType type); + uint32_t irq_id, void *params); void init_mmio_regs(VirtMmioRegs *regs, VirtioDeviceType type); diff --git a/tools/virtio/virtio.c b/tools/virtio/virtio.c index 0b00d61f..0fde4c87 100644 --- a/tools/virtio/virtio.c +++ b/tools/virtio/virtio.c @@ -184,22 +184,57 @@ inline void rw_barrier(void) { #endif } +// --------------------------------------------------------------------------- +// Device ops table — one pointer per device type, defined in each device's .c +static const struct virtio_device_ops *const device_ops_table[] = { + [VirtioTBlock] = &virtio_blk_ops, [VirtioTNet] = &virtio_net_ops, + [VirtioTConsole] = &virtio_console_ops, [VirtioTSCMI] = &virtio_scmi_ops, +#ifdef ENABLE_VIRTIO_GPU + [VirtioTGPU] = &virtio_gpu_ops, +#endif +}; + +static const struct virtio_device_ops *lookup_ops(VirtioDeviceType type) { + int n = (int)(sizeof(device_ops_table) / sizeof(device_ops_table[0])); + if (type <= VirtioTNone || (int)type >= n) + return NULL; + return device_ops_table[type]; +} + +static int init_virtio_queue(VirtIODevice *vdev, + const struct virtio_device_ops *ops); + +// --------------------------------------------------------------------------- +// Device creation — fully table-driven. +// --------------------------------------------------------------------------- + // create a virtio device. VirtIODevice *create_virtio_device(VirtioDeviceType dev_type, uint32_t zone_id, uint64_t base_addr, uint64_t len, - uint32_t irq_id, void *arg0, void *arg1) { + uint32_t irq_id, void *params) { + const struct virtio_device_ops *ops = lookup_ops(dev_type); + if (!ops) { + log_error("unsupported virtio device type %d", dev_type); + return NULL; + } + log_info( "create virtio device type %s, zone id %d, base addr %lx, len %lx, " "irq id %d", virtio_device_type_to_string(dev_type), zone_id, base_addr, len, irq_id); - VirtIODevice *vdev = NULL; - int is_err; - vdev = calloc(1, sizeof(VirtIODevice)); - if (vdev == NULL) { + + if (vdevs_num >= MAX_DEVS) { + log_error("virtio device num exceed max limit"); + return NULL; + } + + VirtIODevice *vdev = calloc(1, sizeof(VirtIODevice)); + if (!vdev) { log_error("failed to allocate virtio device"); return NULL; } + init_mmio_regs(&vdev->regs, dev_type); vdev->base_addr = base_addr; vdev->len = len; @@ -208,158 +243,54 @@ VirtIODevice *create_virtio_device(VirtioDeviceType dev_type, uint32_t zone_id, vdev->type = dev_type; pthread_mutex_init(&vdev->interrupt_lock, NULL); vdev->interrupt_line_asserted = false; - - switch (dev_type) { - case VirtioTBlock: - vdev->regs.dev_feature = BLK_SUPPORTED_FEATURES; - init_blk_dev(vdev); - init_virtio_queue(vdev, dev_type); - log_info("debug: init_blk_dev and init_virtio_queue finished\n"); - is_err = virtio_blk_init(vdev, (const char *)arg0); - break; - - case VirtioTNet: - vdev->regs.dev_feature = NET_SUPPORTED_FEATURES; - vdev->dev = init_net_dev(arg0); - init_virtio_queue(vdev, dev_type); - is_err = virtio_net_init(vdev, (char *)arg1); - break; - - case VirtioTConsole: - vdev->regs.dev_feature = CONSOLE_SUPPORTED_FEATURES; - vdev->dev = init_console_dev(); - init_virtio_queue(vdev, dev_type); - is_err = virtio_console_init(vdev); - break; - - case VirtioTSCMI: - vdev->regs.dev_feature = SCMI_SUPPORTED_FEATURES; - vdev->dev = arg0 ? arg0 : scmi_dev_create(); - vdev->virtio_close = virtio_scmi_close; - init_virtio_queue(vdev, dev_type); - is_err = 0; - break; - - case VirtioTGPU: -#ifdef ENABLE_VIRTIO_GPU - vdev->regs.dev_feature = GPU_SUPPORTED_FEATURES; - vdev->dev = init_gpu_dev((GPURequestedState *)arg0); - free(arg0); - init_virtio_queue(vdev, dev_type); - is_err = virtio_gpu_init(vdev); -#else - log_error("virtio gpu is not enabled"); - goto err; -#endif - break; - - default: - log_error("unsupported virtio device type"); + vdev->regs.dev_feature = ops->features; + vdev->virtio_close = ops->close; + vdev->status_changed = ops->status_changed; + + // Allocate virtqueues before device init: net/console register their + // fds with the already-running event-monitor epoll inside ops->init, + // and the event handlers dereference vdev->vqs. The pre-ops-table + // code also initialized queues first — keep that ordering. + if (init_virtio_queue(vdev, ops) != 0) goto err; - } - - if (is_err) + if (ops->init(vdev, params) != 0) goto err; - // If reaches max number of virtual devices - if (vdevs_num == MAX_DEVS) { - log_error("virtio device num exceed max limit"); - goto err; - } - - if (vdev->dev == NULL) { - log_error("failed to init dev"); - goto err; - } - log_info("create %s success", virtio_device_type_to_string(dev_type)); vdevs[vdevs_num++] = vdev; - return vdev; err: - free(vdev); + ops->close(vdev); return NULL; } -void init_virtio_queue(VirtIODevice *vdev, VirtioDeviceType type) { - VirtQueue *vqs = NULL; - +static int init_virtio_queue(VirtIODevice *vdev, + const struct virtio_device_ops *ops) { log_info("Initializing virtio queue for zone:%d, device type:%s", - vdev->zone_id, virtio_device_type_to_string(type)); + vdev->zone_id, virtio_device_type_to_string(ops->type)); - switch (type) { - case VirtioTBlock: - vdev->vqs_len = 1; - vqs = malloc(sizeof(VirtQueue)); - virtqueue_reset(vqs, 0); - vqs->queue_num_max = VIRTQUEUE_BLK_MAX_SIZE; - vqs->notify_handler = virtio_blk_notify_handler; - vqs->dev = vdev; - vdev->vqs = vqs; - break; - - case VirtioTNet: - vdev->vqs_len = NET_MAX_QUEUES; - vqs = malloc(sizeof(VirtQueue) * NET_MAX_QUEUES); - for (int i = 0; i < NET_MAX_QUEUES; ++i) { - virtqueue_reset(vqs, i); - vqs[i].queue_num_max = VIRTQUEUE_NET_MAX_SIZE; - vqs[i].dev = vdev; - } - vqs[NET_QUEUE_RX].notify_handler = virtio_net_rxq_notify_handler; - vqs[NET_QUEUE_TX].notify_handler = virtio_net_txq_notify_handler; - vdev->vqs = vqs; - break; - - case VirtioTConsole: - vdev->vqs_len = CONSOLE_MAX_QUEUES; - vqs = malloc(sizeof(VirtQueue) * CONSOLE_MAX_QUEUES); - for (int i = 0; i < CONSOLE_MAX_QUEUES; ++i) { - virtqueue_reset(vqs, i); - vqs[i].queue_num_max = VIRTQUEUE_CONSOLE_MAX_SIZE; - vqs[i].dev = vdev; - } - vqs[CONSOLE_QUEUE_RX].notify_handler = - virtio_console_rxq_notify_handler; - vqs[CONSOLE_QUEUE_TX].notify_handler = - virtio_console_txq_notify_handler; - vdev->vqs = vqs; - break; - - case VirtioTGPU: -#ifdef ENABLE_VIRTIO_GPU - vdev->vqs_len = GPU_MAX_QUEUES; - vqs = malloc(sizeof(VirtQueue) * GPU_MAX_QUEUES); - for (int i = 0; i < GPU_MAX_QUEUES; ++i) { - virtqueue_reset(vqs, i); - vqs[i].queue_num_max = VIRTQUEUE_GPU_MAX_SIZE; - vqs[i].dev = vdev; - } - vqs[GPU_CONTROL_QUEUE].notify_handler = virtio_gpu_ctrl_notify_handler; - vqs[GPU_CURSOR_QUEUE].notify_handler = virtio_gpu_cursor_notify_handler; - vdev->vqs = vqs; -#else - log_error("virtio gpu is not enabled"); -#endif - break; + if (ops->num_queues == 0 || ops->num_queues > VIRTIO_MAX_VQUEUES) { + log_error("invalid queue count %u for %s", ops->num_queues, + virtio_device_type_to_string(ops->type)); + return -EINVAL; + } - case VirtioTSCMI: - vdev->vqs_len = SCMI_MAX_QUEUES; - vqs = malloc(sizeof(VirtQueue) * SCMI_MAX_QUEUES); - for (int i = 0; i < SCMI_MAX_QUEUES; ++i) { - virtqueue_reset(vqs, i); - vqs[i].queue_num_max = VIRTQUEUE_SCMI_MAX_SIZE; - vqs[i].dev = vdev; - } - vqs[SCMI_QUEUE_TX].notify_handler = virtio_scmi_txq_notify_handler; - vdev->vqs = vqs; - break; + vdev->vqs_len = ops->num_queues; + VirtQueue *vqs = calloc(ops->num_queues, sizeof(VirtQueue)); + if (!vqs) + return -ENOMEM; - default: - break; + for (uint32_t i = 0; i < ops->num_queues; i++) { + virtqueue_reset(&vqs[i], i); + vqs[i].queue_num_max = ops->queue_max_size; + vqs[i].dev = vdev; + if (ops->notify_handlers[i]) + vqs[i].notify_handler = ops->notify_handlers[i]; } + vdev->vqs = vqs; + return 0; } void init_mmio_regs(VirtMmioRegs *regs, VirtioDeviceType type) { @@ -388,6 +319,9 @@ void virtio_dev_reset(VirtIODevice *vdev) { for (uint32_t i = 0; i < vdev->vqs_len; i++) { virtqueue_reset(&vdev->vqs[i], i); } + const struct virtio_device_ops *ops = lookup_ops(vdev->type); + if (ops && ops->reset) + ops->reset(vdev); vdev->activated = false; } @@ -998,10 +932,15 @@ void virtio_mmio_write(VirtIODevice *vdev, uint64_t offset, uint64_t value, log_debug("****** zone %d %s queue notify begin ******", vdev->zone_id, virtio_device_type_to_string(vdev->type)); - if (value < vdev->vqs_len) { + if (value < vdev->vqs_len && vqs[value].notify_handler) { log_debug("queue notify ready, handler addr is %#x", vqs[value].notify_handler); vqs[value].notify_handler(vdev, &vqs[value]); + } else { + log_warn("zone %d %s: ignoring queue notify, value %" PRIu64 + ", vqs_len %u", + vdev->zone_id, virtio_device_type_to_string(vdev->type), + value, vdev->vqs_len); } log_debug("****** zone %d %s queue notify end ******", vdev->zone_id, @@ -1553,7 +1492,8 @@ int create_virtio_device_from_json(cJSON *device_json, int zone_id) { // Get device type char *type = SAFE_CJSON_GET_OBJECT_ITEM(device_json, "type")->valuestring; - void *arg0 = NULL, *arg1 = NULL; + void *params = NULL; + struct virtio_scmi_init_params scmi_params = {0}; // Mapping table for device types static const struct { @@ -1595,7 +1535,8 @@ int create_virtio_device_from_json(cJSON *device_json, int zone_id) { if (dev_type == VirtioTBlock) { // virtio-blk char *img = SAFE_CJSON_GET_OBJECT_ITEM(device_json, "img")->valuestring; - arg0 = img, arg1 = NULL; + struct virtio_blk_init_params blk_params = {.img_path = img}; + params = &blk_params; log_info("debug: img is %s", img); } else if (dev_type == VirtioTNet) { // virtio-net @@ -1609,10 +1550,11 @@ int create_virtio_device_from_json(cJSON *device_json, int zone_id) { return -1; } } - arg0 = mac, arg1 = tap; + struct virtio_net_init_params net_params = {.mac = mac, .tap = tap}; + params = &net_params; } else if (dev_type == VirtioTConsole) { // virtio-console - arg0 = arg1 = NULL; + params = NULL; } else if (dev_type == VirtioTGPU) { // virtio-gpu #ifdef ENABLE_VIRTIO_GPU @@ -1629,72 +1571,57 @@ int create_virtio_device_from_json(cJSON *device_json, int zone_id) { free(requested_state); return -1; } - arg0 = requested_state; - arg1 = NULL; + params = requested_state; #else log_error( "virtio-gpu is not enabled, please add VIRTIO_GPU=y in make cmd"); return -1; #endif } else if (dev_type == VirtioTSCMI) { - // virtio-scmi - SCMIDev *scmi_dev = scmi_dev_create(); - if (!scmi_dev) { - log_error("Failed to create SCMI device"); - return -1; - } - + // virtio-scmi — just extract ID arrays, wrapper creates SCMIDev + memset(&scmi_params, 0, sizeof(scmi_params)); cJSON *clock_ids = SAFE_CJSON_GET_OBJECT_ITEM(device_json, "clock_ids"); cJSON *reset_ids = SAFE_CJSON_GET_OBJECT_ITEM(device_json, "reset_ids"); cJSON *power_ids = SAFE_CJSON_GET_OBJECT_ITEM(device_json, "power_ids"); - if (scmi_dev_parse_clock_ids(scmi_dev, clock_ids) < 0 || - scmi_dev_parse_reset_ids(scmi_dev, reset_ids) < 0 || - scmi_dev_parse_power_ids(scmi_dev, power_ids) < 0) { - scmi_dev_free(scmi_dev); + if (scmi_dev_parse_clock_ids(&scmi_params, clock_ids) < 0 || + scmi_dev_parse_reset_ids(&scmi_params, reset_ids) < 0 || + scmi_dev_parse_power_ids(&scmi_params, power_ids) < 0) { + scmi_dev_free_params(&scmi_params); return -1; } - /* Register protocols per-device: BASE always, others only if present */ - scmi_dev_register_protocol(scmi_dev, SCMI_PROTO_ID_BASE, - virtio_scmi_base_handle_req); - if (scmi_dev->clock_count > 0) - scmi_dev_register_protocol(scmi_dev, SCMI_PROTO_ID_CLOCK, - virtio_scmi_clock_handle_req); - if (scmi_dev->power_count > 0) - scmi_dev_register_protocol(scmi_dev, SCMI_PROTO_ID_POWER, - virtio_scmi_power_handle_req); - if (scmi_dev->reset_count > 0) - scmi_dev_register_protocol(scmi_dev, SCMI_PROTO_ID_RESET, - virtio_scmi_reset_handle_req); - - arg0 = scmi_dev; - log_info("SCMI device created: clocks=%u resets=%u powers=%u", - scmi_dev->clock_count, scmi_dev->reset_count, - scmi_dev->power_count); + params = &scmi_params; + log_info("SCMI device: clocks=%u resets=%u powers=%u", + scmi_params.clock_count, scmi_params.reset_count, + scmi_params.power_count); } // Check for missing fields if (base_addr == 0 || len == 0 || irq_id == 0) { log_error("missing arguments"); if (dev_type == VirtioTSCMI) - scmi_dev_free(arg0); + scmi_dev_free_params(&scmi_params); #ifdef ENABLE_VIRTIO_GPU if (dev_type == VirtioTGPU) - free(arg0); + free(params); #endif return -1; } // Create virtio_device - if (!create_virtio_device(dev_type, zone_id, base_addr, len, irq_id, arg0, - arg1)) { - if (dev_type == VirtioTSCMI) - scmi_dev_free(arg0); + VirtIODevice *vdev = + create_virtio_device(dev_type, zone_id, base_addr, len, irq_id, params); + + // init_gpu_dev copies what it needs — free regardless of outcome #ifdef ENABLE_VIRTIO_GPU - if (dev_type == VirtioTGPU) - free(arg0); + if (dev_type == VirtioTGPU && params) + free(params); #endif + if (dev_type == VirtioTSCMI) + scmi_dev_free_params(&scmi_params); + + if (!vdev) { return -1; } From e5740a74d6b82f9c5f69939bc0c79933e1158dc9 Mon Sep 17 00:00:00 2001 From: agicy Date: Wed, 12 Aug 2026 02:57:19 +0000 Subject: [PATCH 3/6] feat(virtio): add per-device config parsing ops Add struct virtio_config_ops (parse/free) and move JSON parsing out of create_virtio_device_from_json into each device file: blk's img, net's tap + mac, gpu's width/height, scmi's clock/reset/power id arrays (via scmi_dev_parse_* helpers). parse allocates a typed params struct that create_virtio_device consumes and config_ops->free releases right after. Also fix net MAC parsing to use parse_json_u8: the mac field is an array of hex strings ("0x00", ...) and cJSON_IsNumber() is false for strings. --- tools/virtio/devices/blk/virtio_blk.c | 21 +++ tools/virtio/devices/console/virtio_console.c | 13 ++ tools/virtio/devices/gpu/virtio_gpu_base.c | 22 +++ tools/virtio/devices/net/virtio_net.c | 37 +++++ tools/virtio/devices/scmi/virtio_scmi.c | 29 ++++ tools/virtio/include/virtio.h | 4 + tools/virtio/include/virtio_blk.h | 1 + tools/virtio/include/virtio_console.h | 1 + tools/virtio/include/virtio_gpu.h | 1 + tools/virtio/include/virtio_net.h | 3 +- tools/virtio/include/virtio_scmi.h | 2 + tools/virtio/virtio.c | 127 +++++------------- 12 files changed, 164 insertions(+), 97 deletions(-) diff --git a/tools/virtio/devices/blk/virtio_blk.c b/tools/virtio/devices/blk/virtio_blk.c index 71062f10..1da4134a 100644 --- a/tools/virtio/devices/blk/virtio_blk.c +++ b/tools/virtio/devices/blk/virtio_blk.c @@ -293,3 +293,24 @@ const struct virtio_device_ops virtio_blk_ops = { .reset = virtio_blk_reset, .notify_handlers = {virtio_blk_notify_handler}, }; + +static int virtio_blk_parse_params(cJSON *json, void **out) { + struct virtio_blk_init_params *p = calloc(1, sizeof(*p)); + if (!p) + return -ENOMEM; + cJSON *img = cJSON_GetObjectItem(json, "img"); + if (!cJSON_IsString(img) || !img->valuestring[0]) { + free(p); + return -EINVAL; + } + p->img_path = img->valuestring; + *out = p; + return 0; +} + +static void virtio_blk_free_params(void *params) { free(params); } + +const struct virtio_config_ops virtio_blk_config_ops = { + .parse = virtio_blk_parse_params, + .free = virtio_blk_free_params, +}; diff --git a/tools/virtio/devices/console/virtio_console.c b/tools/virtio/devices/console/virtio_console.c index a2515971..b37a4687 100644 --- a/tools/virtio/devices/console/virtio_console.c +++ b/tools/virtio/devices/console/virtio_console.c @@ -238,4 +238,17 @@ const struct virtio_device_ops virtio_console_ops = { [CONSOLE_QUEUE_RX] = virtio_console_rxq_notify_handler, [CONSOLE_QUEUE_TX] = virtio_console_txq_notify_handler, }, +}; + +static int virtio_console_parse_params(cJSON *json, void **out) { + (void)json; + *out = NULL; + return 0; +} + +static void virtio_console_free_params(void *params) { (void)params; } + +const struct virtio_config_ops virtio_console_config_ops = { + .parse = virtio_console_parse_params, + .free = virtio_console_free_params, }; \ No newline at end of file diff --git a/tools/virtio/devices/gpu/virtio_gpu_base.c b/tools/virtio/devices/gpu/virtio_gpu_base.c index 8e4cad20..15f7438c 100644 --- a/tools/virtio/devices/gpu/virtio_gpu_base.c +++ b/tools/virtio/devices/gpu/virtio_gpu_base.c @@ -8,6 +8,7 @@  * Authors:  *        */ +#include "json_parse.h" #include "log.h" #include "sys/queue.h" #include "unistd.h" @@ -271,6 +272,27 @@ const struct virtio_device_ops virtio_gpu_ops = { }, }; +static int virtio_gpu_parse_params(cJSON *json, void **out) { + GPURequestedState *s = calloc(1, sizeof(*s)); + if (!s) + return -ENOMEM; + + if (parse_json_u32(cJSON_GetObjectItem(json, "width"), &s->width) != 0 || + parse_json_u32(cJSON_GetObjectItem(json, "height"), &s->height) != 0) { + free(s); + return -EINVAL; + } + *out = s; + return 0; +} + +static void virtio_gpu_free_params(void *params) { free(params); } + +const struct virtio_config_ops virtio_gpu_config_ops = { + .parse = virtio_gpu_parse_params, + .free = virtio_gpu_free_params, +}; + int virtio_gpu_ctrl_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { log_debug("entering %s", __func__); diff --git a/tools/virtio/devices/net/virtio_net.c b/tools/virtio/devices/net/virtio_net.c index 7f0e2dcb..8371e097 100644 --- a/tools/virtio/devices/net/virtio_net.c +++ b/tools/virtio/devices/net/virtio_net.c @@ -10,6 +10,7 @@  */ #include "virtio_net.h" #include "event_monitor.h" +#include "json_parse.h" #include "log.h" #include "virtio.h" @@ -361,3 +362,39 @@ const struct virtio_device_ops virtio_net_ops = { [NET_QUEUE_TX] = virtio_net_txq_notify_handler, }, }; + +static int virtio_net_parse_params(cJSON *json, void **out) { + struct virtio_net_init_params *p = calloc(1, sizeof(*p)); + if (!p) + return -ENOMEM; + + cJSON *tap = cJSON_GetObjectItem(json, "tap"); + if (!cJSON_IsString(tap) || !tap->valuestring[0]) { + free(p); + return -EINVAL; + } + p->tap = tap->valuestring; + + cJSON *mac_json = cJSON_GetObjectItem(json, "mac"); + if (cJSON_GetArraySize(mac_json) != 6) { + free(p); + return -EINVAL; + } + for (int i = 0; i < 6; i++) { + if (parse_json_u8(cJSON_GetArrayItem(mac_json, i), &p->mac[i]) != 0) { + log_error("failed to parse mac byte %d", i); + free(p); + return -EINVAL; + } + } + + *out = p; + return 0; +} + +static void virtio_net_free_params(void *params) { free(params); } + +const struct virtio_config_ops virtio_net_config_ops = { + .parse = virtio_net_parse_params, + .free = virtio_net_free_params, +}; diff --git a/tools/virtio/devices/scmi/virtio_scmi.c b/tools/virtio/devices/scmi/virtio_scmi.c index 9f7b9d7e..1601c1a2 100644 --- a/tools/virtio/devices/scmi/virtio_scmi.c +++ b/tools/virtio/devices/scmi/virtio_scmi.c @@ -265,3 +265,32 @@ const struct virtio_device_ops virtio_scmi_ops = { [SCMI_QUEUE_TX] = virtio_scmi_txq_notify_handler, }, }; + +static int virtio_scmi_parse_params(cJSON *json, void **out) { + struct virtio_scmi_init_params *p = calloc(1, sizeof(*p)); + if (!p) + return -ENOMEM; + + cJSON *clock_ids = cJSON_GetObjectItem(json, "clock_ids"); + cJSON *reset_ids = cJSON_GetObjectItem(json, "reset_ids"); + cJSON *power_ids = cJSON_GetObjectItem(json, "power_ids"); + + if (scmi_dev_parse_clock_ids(p, clock_ids) < 0 || + scmi_dev_parse_reset_ids(p, reset_ids) < 0 || + scmi_dev_parse_power_ids(p, power_ids) < 0) { + scmi_dev_free_params(p); + return -EINVAL; + } + + *out = p; + return 0; +} + +static void virtio_scmi_free_params(void *params) { + scmi_dev_free_params(params); +} + +const struct virtio_config_ops virtio_scmi_config_ops = { + .parse = virtio_scmi_parse_params, + .free = virtio_scmi_free_params, +}; diff --git a/tools/virtio/include/virtio.h b/tools/virtio/include/virtio.h index 83c736ed..9ef82deb 100644 --- a/tools/virtio/include/virtio.h +++ b/tools/virtio/include/virtio.h @@ -144,6 +144,10 @@ struct virtio_device_ops { int (*notify_handlers[VIRTIO_MAX_VQUEUES])(VirtIODevice *, VirtQueue *); }; +struct virtio_config_ops { + int (*parse)(cJSON *json, void **params_out); + void (*free)(void *params); +}; // used event idx for driver telling device when to notify driver. #define VQ_USED_EVENT(vq) ((vq)->avail_ring->ring[(vq)->num]) // avail event idx for device telling driver when to notify device. diff --git a/tools/virtio/include/virtio_blk.h b/tools/virtio/include/virtio_blk.h index 34754f79..fef50a7d 100644 --- a/tools/virtio/include/virtio_blk.h +++ b/tools/virtio/include/virtio_blk.h @@ -63,5 +63,6 @@ void virtio_blk_close(VirtIODevice *vdev); void virtio_blk_reset(VirtIODevice *vdev); extern const struct virtio_device_ops virtio_blk_ops; +extern const struct virtio_config_ops virtio_blk_config_ops; #endif /* _HVISOR_VIRTIO_BLK_H */ diff --git a/tools/virtio/include/virtio_console.h b/tools/virtio/include/virtio_console.h index eacdaa9d..c5e773f9 100644 --- a/tools/virtio/include/virtio_console.h +++ b/tools/virtio/include/virtio_console.h @@ -38,5 +38,6 @@ void virtio_console_close(VirtIODevice *vdev); void virtio_console_reset(VirtIODevice *vdev); extern const struct virtio_device_ops virtio_console_ops; +extern const struct virtio_config_ops virtio_console_config_ops; #endif \ No newline at end of file diff --git a/tools/virtio/include/virtio_gpu.h b/tools/virtio/include/virtio_gpu.h index 9f1d5282..fcb6688c 100644 --- a/tools/virtio/include/virtio_gpu.h +++ b/tools/virtio/include/virtio_gpu.h @@ -224,6 +224,7 @@ void virtio_gpu_close(VirtIODevice *vdev); void virtio_gpu_reset(VirtIODevice *vdev); extern const struct virtio_device_ops virtio_gpu_ops; +extern const struct virtio_config_ops virtio_gpu_config_ops; // Handler function when controlq has requests to process int virtio_gpu_ctrl_notify_handler(VirtIODevice *vdev, VirtQueue *vq); diff --git a/tools/virtio/include/virtio_net.h b/tools/virtio/include/virtio_net.h index 79934963..6c8eb490 100644 --- a/tools/virtio/include/virtio_net.h +++ b/tools/virtio/include/virtio_net.h @@ -24,7 +24,7 @@ #define VIRTQUEUE_NET_MAX_SIZE 256 struct virtio_net_init_params { - const uint8_t *mac; + uint8_t mac[6]; const char *tap; }; @@ -65,5 +65,6 @@ void virtio_net_reset(VirtIODevice *vdev); void net_on_status(VirtIODevice *vdev, uint32_t status); extern const struct virtio_device_ops virtio_net_ops; +extern const struct virtio_config_ops virtio_net_config_ops; #endif //_HVISOR_VIRTIO_NET_H diff --git a/tools/virtio/include/virtio_scmi.h b/tools/virtio/include/virtio_scmi.h index 4180b2ca..67f387c9 100644 --- a/tools/virtio/include/virtio_scmi.h +++ b/tools/virtio/include/virtio_scmi.h @@ -274,4 +274,6 @@ struct hvisor_scmi_ioctl_hdr { int hvisor_scmi_ioctl_cmd(int ioctl_cmd, void *args, size_t args_size, uint32_t subcmd, const char *proto_name); +extern const struct virtio_config_ops virtio_scmi_config_ops; + #endif diff --git a/tools/virtio/virtio.c b/tools/virtio/virtio.c index 0fde4c87..e6535e77 100644 --- a/tools/virtio/virtio.c +++ b/tools/virtio/virtio.c @@ -201,6 +201,24 @@ static const struct virtio_device_ops *lookup_ops(VirtioDeviceType type) { return device_ops_table[type]; } +static const struct virtio_config_ops *const config_ops_table[] = { + [VirtioTBlock] = &virtio_blk_config_ops, + [VirtioTNet] = &virtio_net_config_ops, + [VirtioTConsole] = &virtio_console_config_ops, + [VirtioTSCMI] = &virtio_scmi_config_ops, +#ifdef ENABLE_VIRTIO_GPU + [VirtioTGPU] = &virtio_gpu_config_ops, +#endif +}; + +static const struct virtio_config_ops * +lookup_config_ops(VirtioDeviceType type) { + int n = (int)(sizeof(config_ops_table) / sizeof(config_ops_table[0])); + if (type <= VirtioTNone || (int)type >= n) + return NULL; + return config_ops_table[type]; +} + static int init_virtio_queue(VirtIODevice *vdev, const struct virtio_device_ops *ops); @@ -1481,46 +1499,36 @@ int virtio_init() { } int create_virtio_device_from_json(cJSON *device_json, int zone_id) { - VirtioDeviceType dev_type = VirtioTNone; - uint64_t base_addr = 0, len = 0; - uint32_t irq_id = 0; - char *status = SAFE_CJSON_GET_OBJECT_ITEM(device_json, "status")->valuestring; if (strcmp(status, "disable") == 0) return 0; - // Get device type char *type = SAFE_CJSON_GET_OBJECT_ITEM(device_json, "type")->valuestring; - void *params = NULL; - struct virtio_scmi_init_params scmi_params = {0}; - // Mapping table for device types static const struct { const char *name; VirtioDeviceType type; } device_type_map[] = { {"blk", VirtioTBlock}, {"net", VirtioTNet}, {"console", VirtioTConsole}, {"gpu", VirtioTGPU}, - {"scmi", VirtioTSCMI}, {NULL, VirtioTNone} // Sentinel + {"scmi", VirtioTSCMI}, {NULL, VirtioTNone}, }; - // Find device type in mapping table - dev_type = VirtioTNone; + VirtioDeviceType dev_type = VirtioTNone; for (int i = 0; device_type_map[i].name != NULL; i++) { if (strcmp(type, device_type_map[i].name) == 0) { dev_type = device_type_map[i].type; break; } } - if (dev_type == VirtioTNone) { log_error("unknown device type %s", type); return -1; } - // Get base_addr, len, irq_id (mmio region base address and length, device - // interrupt number) + uint64_t base_addr = 0, len = 0; + uint32_t irq_id = 0; if (parse_json_u64(SAFE_CJSON_GET_OBJECT_ITEM(device_json, "addr"), &base_addr) != 0 || parse_json_u64(SAFE_CJSON_GET_OBJECT_ITEM(device_json, "len"), &len) != @@ -1531,99 +1539,26 @@ int create_virtio_device_from_json(cJSON *device_json, int zone_id) { return -1; } - // Handle other fields according to the device type - if (dev_type == VirtioTBlock) { - // virtio-blk - char *img = SAFE_CJSON_GET_OBJECT_ITEM(device_json, "img")->valuestring; - struct virtio_blk_init_params blk_params = {.img_path = img}; - params = &blk_params; - log_info("debug: img is %s", img); - } else if (dev_type == VirtioTNet) { - // virtio-net - char *tap = SAFE_CJSON_GET_OBJECT_ITEM(device_json, "tap")->valuestring; - cJSON *mac_json = SAFE_CJSON_GET_OBJECT_ITEM(device_json, "mac"); - uint8_t mac[6]; - for (int i = 0; i < 6; i++) { - if (parse_json_u8(SAFE_CJSON_GET_ARRAY_ITEM(mac_json, i), - &mac[i]) != 0) { - log_error("failed to parse mac address"); - return -1; - } - } - struct virtio_net_init_params net_params = {.mac = mac, .tap = tap}; - params = &net_params; - } else if (dev_type == VirtioTConsole) { - // virtio-console - params = NULL; - } else if (dev_type == VirtioTGPU) { -// virtio-gpu -#ifdef ENABLE_VIRTIO_GPU - // TODO: Add display device settings - GPURequestedState *requested_state = NULL; - requested_state = - (GPURequestedState *)malloc(sizeof(GPURequestedState)); - memset(requested_state, 0, sizeof(GPURequestedState)); - if (parse_json_u32(SAFE_CJSON_GET_OBJECT_ITEM(device_json, "width"), - &requested_state->width) != 0 || - parse_json_u32(SAFE_CJSON_GET_OBJECT_ITEM(device_json, "height"), - &requested_state->height) != 0) { - log_error("failed to parse gpu width or height"); - free(requested_state); - return -1; - } - params = requested_state; -#else - log_error( - "virtio-gpu is not enabled, please add VIRTIO_GPU=y in make cmd"); + if (base_addr == 0 || len == 0 || irq_id == 0) { + log_error("missing arguments"); return -1; -#endif - } else if (dev_type == VirtioTSCMI) { - // virtio-scmi — just extract ID arrays, wrapper creates SCMIDev - memset(&scmi_params, 0, sizeof(scmi_params)); - cJSON *clock_ids = SAFE_CJSON_GET_OBJECT_ITEM(device_json, "clock_ids"); - cJSON *reset_ids = SAFE_CJSON_GET_OBJECT_ITEM(device_json, "reset_ids"); - cJSON *power_ids = SAFE_CJSON_GET_OBJECT_ITEM(device_json, "power_ids"); - - if (scmi_dev_parse_clock_ids(&scmi_params, clock_ids) < 0 || - scmi_dev_parse_reset_ids(&scmi_params, reset_ids) < 0 || - scmi_dev_parse_power_ids(&scmi_params, power_ids) < 0) { - scmi_dev_free_params(&scmi_params); - return -1; - } - - params = &scmi_params; - log_info("SCMI device: clocks=%u resets=%u powers=%u", - scmi_params.clock_count, scmi_params.reset_count, - scmi_params.power_count); } - // Check for missing fields - if (base_addr == 0 || len == 0 || irq_id == 0) { - log_error("missing arguments"); - if (dev_type == VirtioTSCMI) - scmi_dev_free_params(&scmi_params); -#ifdef ENABLE_VIRTIO_GPU - if (dev_type == VirtioTGPU) - free(params); -#endif + const struct virtio_config_ops *cfg_ops = lookup_config_ops(dev_type); + void *params = NULL; + if (cfg_ops && cfg_ops->parse && + cfg_ops->parse(device_json, ¶ms) != 0) { return -1; } - // Create virtio_device VirtIODevice *vdev = create_virtio_device(dev_type, zone_id, base_addr, len, irq_id, params); - // init_gpu_dev copies what it needs — free regardless of outcome -#ifdef ENABLE_VIRTIO_GPU - if (dev_type == VirtioTGPU && params) - free(params); -#endif - if (dev_type == VirtioTSCMI) - scmi_dev_free_params(&scmi_params); + if (cfg_ops && cfg_ops->free) + cfg_ops->free(params); - if (!vdev) { + if (!vdev) return -1; - } return 0; } From a28a42329ff58b85840e722d460912ff9d939555 Mon Sep 17 00:00:00 2001 From: agicy Date: Wed, 12 Aug 2026 02:57:19 +0000 Subject: [PATCH 4/6] cleanup(virtio): harden close paths and make device internals static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NULL-guard every device close(): bail on NULL vdev, guard the per-dev state (dev->mtx/cond/img_fd), and null out freed pointers. Make all device init/notify/close/reset functions static and drop their declarations from the device headers — only the *_ops externs stay exported. --- tools/virtio/devices/blk/virtio_blk.c | 36 +++++++----- tools/virtio/devices/console/virtio_console.c | 31 ++++++---- tools/virtio/devices/gpu/virtio_gpu_base.c | 57 ++++++++++--------- tools/virtio/devices/net/virtio_net.c | 34 ++++++----- tools/virtio/devices/scmi/virtio_scmi.c | 15 +++-- tools/virtio/include/virtio_blk.h | 6 -- tools/virtio/include/virtio_console.h | 7 --- tools/virtio/include/virtio_gpu.h | 6 +- tools/virtio/include/virtio_net.h | 11 ---- tools/virtio/include/virtio_scmi.h | 3 - 10 files changed, 106 insertions(+), 100 deletions(-) diff --git a/tools/virtio/devices/blk/virtio_blk.c b/tools/virtio/devices/blk/virtio_blk.c index 1da4134a..8359a3f9 100644 --- a/tools/virtio/devices/blk/virtio_blk.c +++ b/tools/virtio/devices/blk/virtio_blk.c @@ -128,7 +128,7 @@ static void *blkproc_thread(void *arg) { } // create blk dev. -BlkDev *init_blk_dev(VirtIODevice *vdev) { +static BlkDev *init_blk_dev(VirtIODevice *vdev) { BlkDev *dev = malloc(sizeof(BlkDev)); vdev->dev = dev; dev->config.capacity = -1; @@ -145,7 +145,7 @@ BlkDev *init_blk_dev(VirtIODevice *vdev) { return dev; } -int virtio_blk_init(VirtIODevice *vdev, const char *img_path) { +static int virtio_blk_init(VirtIODevice *vdev, const char *img_path) { int img_fd = open(img_path, O_RDWR); BlkDev *dev = vdev->dev; struct stat st; @@ -226,7 +226,7 @@ static struct blkp_req *virtq_blk_handle_one_request(VirtQueue *vq) { return NULL; } -int virtio_blk_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { +static int virtio_blk_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { log_debug("virtio blk notify handler enter"); BlkDev *blkDev = (BlkDev *)vdev->dev; struct blkp_req *breq; @@ -251,24 +251,32 @@ int virtio_blk_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { return 0; } -void virtio_blk_reset(VirtIODevice *vdev) { (void)vdev; } +static void virtio_blk_reset(VirtIODevice *vdev) { (void)vdev; } /* * Shut down the blk device: signal close, wait for the worker to exit, * then release all resources. */ -void virtio_blk_close(VirtIODevice *vdev) { +static void virtio_blk_close(VirtIODevice *vdev) { + if (!vdev) + return; + BlkDev *dev = vdev->dev; - pthread_mutex_lock(&dev->mtx); - dev->close = 1; - pthread_cond_signal(&dev->cond); - pthread_mutex_unlock(&dev->mtx); - pthread_join(dev->tid, NULL); - pthread_mutex_destroy(&dev->mtx); - pthread_cond_destroy(&dev->cond); - close(dev->img_fd); - free(dev); + if (dev) { + pthread_mutex_lock(&dev->mtx); + dev->close = 1; + pthread_cond_signal(&dev->cond); + pthread_mutex_unlock(&dev->mtx); + pthread_join(dev->tid, NULL); + pthread_mutex_destroy(&dev->mtx); + pthread_cond_destroy(&dev->cond); + if (dev->img_fd >= 0) + close(dev->img_fd); + free(dev); + vdev->dev = NULL; + } free(vdev->vqs); + vdev->vqs = NULL; free(vdev); } diff --git a/tools/virtio/devices/console/virtio_console.c b/tools/virtio/devices/console/virtio_console.c index b37a4687..a5ad56e1 100644 --- a/tools/virtio/devices/console/virtio_console.c +++ b/tools/virtio/devices/console/virtio_console.c @@ -23,7 +23,7 @@ static uint8_t trashbuf[1024]; -ConsoleDev *init_console_dev() { +static ConsoleDev *init_console_dev() { ConsoleDev *dev = (ConsoleDev *)malloc(sizeof(ConsoleDev)); dev->config.cols = 80; dev->config.rows = 25; @@ -87,7 +87,7 @@ static void virtio_console_event_handler(int fd, int epoll_type, void *param) { return; } -int virtio_console_init(VirtIODevice *vdev) { +static int virtio_console_init(VirtIODevice *vdev) { ConsoleDev *dev = (ConsoleDev *)vdev->dev; int master_fd, slave_fd; char *slave_name; @@ -156,7 +156,8 @@ int virtio_console_init(VirtIODevice *vdev) { return 0; } -int virtio_console_rxq_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { +static int virtio_console_rxq_notify_handler(VirtIODevice *vdev, + VirtQueue *vq) { log_debug("%s", __func__); ConsoleDev *dev = (ConsoleDev *)vdev->dev; if (dev->rx_ready <= 0) { @@ -190,7 +191,8 @@ static void virtq_tx_handle_one_request(ConsoleDev *dev, VirtQueue *vq) { free(iov); } -int virtio_console_txq_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { +static int virtio_console_txq_notify_handler(VirtIODevice *vdev, + VirtQueue *vq) { log_debug("%s", __func__); while (!virtqueue_is_empty(vq)) { virtqueue_disable_notify(vq); @@ -203,17 +205,24 @@ int virtio_console_txq_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { return 0; } -void virtio_console_reset(VirtIODevice *vdev) { (void)vdev; } +static void virtio_console_reset(VirtIODevice *vdev) { (void)vdev; } + +static void virtio_console_close(VirtIODevice *vdev) { + if (!vdev) + return; -void virtio_console_close(VirtIODevice *vdev) { ConsoleDev *dev = vdev->dev; - close(dev->master_fd); - if (dev->slave_keepalive_fd >= 0) { - close(dev->slave_keepalive_fd); + if (dev) { + if (dev->master_fd >= 0) + close(dev->master_fd); + if (dev->slave_keepalive_fd >= 0) + close(dev->slave_keepalive_fd); + free(dev->event); + free(dev); + vdev->dev = NULL; } - free(dev->event); - free(dev); free(vdev->vqs); + vdev->vqs = NULL; free(vdev); } diff --git a/tools/virtio/devices/gpu/virtio_gpu_base.c b/tools/virtio/devices/gpu/virtio_gpu_base.c index 15f7438c..0e950eee 100644 --- a/tools/virtio/devices/gpu/virtio_gpu_base.c +++ b/tools/virtio/devices/gpu/virtio_gpu_base.c @@ -24,7 +24,7 @@ #include #include -GPUDev *init_gpu_dev(GPURequestedState *requested_state) { +static GPUDev *init_gpu_dev(GPURequestedState *requested_state) { log_info("initializing GPUDev"); if (requested_state == NULL) { @@ -92,7 +92,7 @@ GPUDev *init_gpu_dev(GPURequestedState *requested_state) { return gdev; } -int virtio_gpu_init(VirtIODevice *vdev) { +static int virtio_gpu_init(VirtIODevice *vdev) { log_info("entering %s", __func__); // TODO: Display device initialization @@ -179,11 +179,12 @@ int virtio_gpu_init(VirtIODevice *vdev) { pthread_create(&gdev->gpu_thread, NULL, virtio_gpu_handler, vdev); pthread_cond_init(&gdev->gpu_cond, NULL); pthread_mutex_init(&gdev->queue_mutex, NULL); + gdev->async_started = true; return 0; } -void virtio_gpu_close(VirtIODevice *vdev) { +static void virtio_gpu_close(VirtIODevice *vdev) { if (!vdev) return; @@ -222,10 +223,14 @@ void virtio_gpu_close(VirtIODevice *vdev) { // Reclaim async part gdev->close = true; - pthread_cond_signal(&gdev->gpu_cond); - pthread_join(gdev->gpu_thread, NULL); - pthread_cond_destroy(&gdev->gpu_cond); - pthread_mutex_destroy(&gdev->queue_mutex); + // gpu_cond/gpu_thread only exist once virtio_gpu_init finished; + // on a partial init (e.g. drm open failure) skip them entirely. + if (gdev->async_started) { + pthread_cond_signal(&gdev->gpu_cond); + pthread_join(gdev->gpu_thread, NULL); + pthread_cond_destroy(&gdev->gpu_cond); + pthread_mutex_destroy(&gdev->queue_mutex); + } free(gdev); vdev->dev = NULL; @@ -236,7 +241,7 @@ void virtio_gpu_close(VirtIODevice *vdev) { free(vdev); } -void virtio_gpu_reset(VirtIODevice *vdev) { +static void virtio_gpu_reset(VirtIODevice *vdev) { if (!vdev || !vdev->dev) return; @@ -257,22 +262,7 @@ static int virtio_gpu_do_init(VirtIODevice *vdev, void *params) { return virtio_gpu_init(vdev); } -const struct virtio_device_ops virtio_gpu_ops = { - .type = VirtioTGPU, - .features = GPU_SUPPORTED_FEATURES, - .num_queues = GPU_MAX_QUEUES, - .queue_max_size = VIRTQUEUE_GPU_MAX_SIZE, - .init = virtio_gpu_do_init, - .close = virtio_gpu_close, - .reset = virtio_gpu_reset, - .notify_handlers = - { - [GPU_CONTROL_QUEUE] = virtio_gpu_ctrl_notify_handler, - [GPU_CURSOR_QUEUE] = virtio_gpu_cursor_notify_handler, - }, -}; - -static int virtio_gpu_parse_params(cJSON *json, void **out) { +static int virtio_gpu_parse_params(const cJSON *json, void **out) { GPURequestedState *s = calloc(1, sizeof(*s)); if (!s) return -ENOMEM; @@ -293,7 +283,7 @@ const struct virtio_config_ops virtio_gpu_config_ops = { .free = virtio_gpu_free_params, }; -int virtio_gpu_ctrl_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { +static int virtio_gpu_ctrl_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { log_debug("entering %s", __func__); GPUDev *gdev = vdev->dev; @@ -321,7 +311,7 @@ int virtio_gpu_ctrl_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { return 0; } -int virtio_gpu_cursor_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { +static int virtio_gpu_cursor_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { log_debug("entering %s", __func__); virtqueue_disable_notify(vq); @@ -340,6 +330,21 @@ int virtio_gpu_cursor_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { return 0; } +const struct virtio_device_ops virtio_gpu_ops = { + .type = VirtioTGPU, + .features = GPU_SUPPORTED_FEATURES, + .num_queues = GPU_MAX_QUEUES, + .queue_max_size = VIRTQUEUE_GPU_MAX_SIZE, + .init = virtio_gpu_do_init, + .close = virtio_gpu_close, + .reset = virtio_gpu_reset, + .notify_handlers = + { + [GPU_CONTROL_QUEUE] = virtio_gpu_ctrl_notify_handler, + [GPU_CURSOR_QUEUE] = virtio_gpu_cursor_notify_handler, + }, +}; + int virtio_gpu_handle_single_request(VirtIODevice *vdev, VirtQueue *vq, uint32_t from) { // virtio-gpu dev diff --git a/tools/virtio/devices/net/virtio_net.c b/tools/virtio/devices/net/virtio_net.c index 8371e097..d5212f76 100644 --- a/tools/virtio/devices/net/virtio_net.c +++ b/tools/virtio/devices/net/virtio_net.c @@ -24,7 +24,7 @@ #include #include -NetDev *init_net_dev(uint8_t mac[]) { +static NetDev *init_net_dev(uint8_t mac[]) { NetDev *dev = malloc(sizeof(NetDev)); dev->config.mac[0] = mac[0]; dev->config.mac[1] = mac[1]; @@ -67,7 +67,7 @@ static int open_tap(char *devname) { } /// When driver notifies rxq, it means the rx process can now begin -int virtio_net_rxq_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { +static int virtio_net_rxq_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { log_debug("virtio_net_rxq_notify_handler"); NetDev *net = vdev->dev; if (net->rx_ready <= 0) { @@ -89,7 +89,7 @@ size_t get_nethdr_size(VirtIODevice *vdev) { } /// Called when tap device received packets -void virtio_net_event_handler(int fd, int epoll_type, void *param) { +static void virtio_net_event_handler(int fd, int epoll_type, void *param) { log_debug("virtio_net_event_handler"); VirtIODevice *vdev = param; NetDev *net = vdev->dev; @@ -235,7 +235,7 @@ static void virtq_tx_handle_one_request(VirtIODevice *vdev, VirtQueue *vq, (*out_count)++; } -int virtio_net_txq_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { +static int virtio_net_txq_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { log_debug("virtio_net_txq_notify_handler"); virtqueue_disable_notify(vq); uint16_t batch_indices[VIRTQUEUE_NET_MAX_SIZE]; @@ -265,7 +265,7 @@ int virtio_net_txq_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { return 0; } -void net_on_status(VirtIODevice *vdev, uint32_t status) { +static void net_on_status(VirtIODevice *vdev, uint32_t status) { NetDev *net = vdev->dev; // FEATURES_OK indicates guest has finished writing DRIVER_FEATURES. @@ -281,7 +281,7 @@ void net_on_status(VirtIODevice *vdev, uint32_t status) { } } -int virtio_net_init(VirtIODevice *vdev, char *devname) { +static int virtio_net_init(VirtIODevice *vdev, char *devname) { log_info("virtio net init"); NetDev *net = vdev->dev; // open tap device @@ -319,21 +319,29 @@ int virtio_net_init(VirtIODevice *vdev, char *devname) { return 0; } -void virtio_net_reset(VirtIODevice *vdev) { +static void virtio_net_reset(VirtIODevice *vdev) { if (!vdev || !vdev->dev) return; NetDev *dev = vdev->dev; dev->rx_ready = false; } -void virtio_net_close(VirtIODevice *vdev) { +static void virtio_net_close(VirtIODevice *vdev) { + if (!vdev) + return; + NetDev *dev = vdev->dev; - close(dev->tapfd); - free(dev->event); - free(dev->in_iov); - free(dev->out_iov); - free(dev); + if (dev) { + if (dev->tapfd >= 0) + close(dev->tapfd); + free(dev->event); + free(dev->in_iov); + free(dev->out_iov); + free(dev); + vdev->dev = NULL; + } free(vdev->vqs); + vdev->vqs = NULL; free(vdev); } diff --git a/tools/virtio/devices/scmi/virtio_scmi.c b/tools/virtio/devices/scmi/virtio_scmi.c index 1601c1a2..bceb5bd9 100644 --- a/tools/virtio/devices/scmi/virtio_scmi.c +++ b/tools/virtio/devices/scmi/virtio_scmi.c @@ -158,7 +158,7 @@ static int virtq_tx_handle_one_request(void *dev, VirtQueue *vq) { return 0; } -int virtio_scmi_txq_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { +static int virtio_scmi_txq_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { while (!virtqueue_is_empty(vq)) { virtqueue_disable_notify(vq); while (!virtqueue_is_empty(vq)) { @@ -177,12 +177,19 @@ int virtio_scmi_txq_notify_handler(VirtIODevice *vdev, VirtQueue *vq) { return 0; } -void virtio_scmi_reset(VirtIODevice *vdev) { (void)vdev; } +static void virtio_scmi_reset(VirtIODevice *vdev) { (void)vdev; } + +static void virtio_scmi_close(VirtIODevice *vdev) { + if (!vdev) + return; -void virtio_scmi_close(VirtIODevice *vdev) { SCMIDev *dev = vdev->dev; - scmi_dev_free(dev); + if (dev) { + scmi_dev_free(dev); + vdev->dev = NULL; + } free(vdev->vqs); + vdev->vqs = NULL; free(vdev); } diff --git a/tools/virtio/include/virtio_blk.h b/tools/virtio/include/virtio_blk.h index fef50a7d..a89f5e3b 100644 --- a/tools/virtio/include/virtio_blk.h +++ b/tools/virtio/include/virtio_blk.h @@ -56,12 +56,6 @@ struct virtio_blk_init_params { const char *img_path; }; -BlkDev *init_blk_dev(VirtIODevice *vdev); -int virtio_blk_init(VirtIODevice *vdev, const char *img_path); -int virtio_blk_notify_handler(VirtIODevice *vdev, VirtQueue *vq); -void virtio_blk_close(VirtIODevice *vdev); -void virtio_blk_reset(VirtIODevice *vdev); - extern const struct virtio_device_ops virtio_blk_ops; extern const struct virtio_config_ops virtio_blk_config_ops; diff --git a/tools/virtio/include/virtio_console.h b/tools/virtio/include/virtio_console.h index c5e773f9..7a6252ae 100644 --- a/tools/virtio/include/virtio_console.h +++ b/tools/virtio/include/virtio_console.h @@ -30,13 +30,6 @@ typedef struct virtio_console_dev { struct hvisor_event *event; } ConsoleDev; -ConsoleDev *init_console_dev(); -int virtio_console_init(VirtIODevice *vdev); -int virtio_console_rxq_notify_handler(VirtIODevice *vdev, VirtQueue *vq); -int virtio_console_txq_notify_handler(VirtIODevice *vdev, VirtQueue *vq); -void virtio_console_close(VirtIODevice *vdev); -void virtio_console_reset(VirtIODevice *vdev); - extern const struct virtio_device_ops virtio_console_ops; extern const struct virtio_config_ops virtio_console_config_ops; diff --git a/tools/virtio/include/virtio_gpu.h b/tools/virtio/include/virtio_gpu.h index fcb6688c..fd69590c 100644 --- a/tools/virtio/include/virtio_gpu.h +++ b/tools/virtio/include/virtio_gpu.h @@ -193,6 +193,7 @@ typedef struct virtio_gpu_dev { pthread_cond_t gpu_cond; pthread_mutex_t queue_mutex; bool close; + bool async_started; // True once the async worker thread exists } GPUDev; typedef struct virtio_gpu_control_cmd { @@ -215,22 +216,17 @@ typedef struct virtio_gpu_control_cmd { GPUDev *init_gpu_dev(GPURequestedState *requested_states); // Initialize virtio-gpu device -int virtio_gpu_init(VirtIODevice *vdev); // Close virtio-gpu device -void virtio_gpu_close(VirtIODevice *vdev); // Reset virtio-gpu device -void virtio_gpu_reset(VirtIODevice *vdev); extern const struct virtio_device_ops virtio_gpu_ops; extern const struct virtio_config_ops virtio_gpu_config_ops; // Handler function when controlq has requests to process -int virtio_gpu_ctrl_notify_handler(VirtIODevice *vdev, VirtQueue *vq); // Handler function when cursorq has requests to process -int virtio_gpu_cursor_notify_handler(VirtIODevice *vdev, VirtQueue *vq); // Process a single request int virtio_gpu_handle_single_request(VirtIODevice *vdev, VirtQueue *vq, diff --git a/tools/virtio/include/virtio_net.h b/tools/virtio/include/virtio_net.h index 6c8eb490..5b71c856 100644 --- a/tools/virtio/include/virtio_net.h +++ b/tools/virtio/include/virtio_net.h @@ -53,17 +53,6 @@ typedef struct virtio_net_dev { struct iovec *out_iov; } NetDev; -NetDev *init_net_dev(uint8_t mac[]); - -int virtio_net_rxq_notify_handler(VirtIODevice *vdev, VirtQueue *vq); -int virtio_net_txq_notify_handler(VirtIODevice *vdev, VirtQueue *vq); - -void virtio_net_event_handler(int fd, int epoll_type, void *param); -int virtio_net_init(VirtIODevice *vdev, char *devname); -void virtio_net_close(VirtIODevice *vdev); -void virtio_net_reset(VirtIODevice *vdev); -void net_on_status(VirtIODevice *vdev, uint32_t status); - extern const struct virtio_device_ops virtio_net_ops; extern const struct virtio_config_ops virtio_net_config_ops; diff --git a/tools/virtio/include/virtio_scmi.h b/tools/virtio/include/virtio_scmi.h index 67f387c9..0486e5eb 100644 --- a/tools/virtio/include/virtio_scmi.h +++ b/tools/virtio/include/virtio_scmi.h @@ -246,9 +246,6 @@ struct virtio_scmi_init_params { SCMIDev *scmi_dev_create(void); void scmi_dev_free(SCMIDev *dev); -int virtio_scmi_txq_notify_handler(VirtIODevice *vdev, VirtQueue *vq); -void virtio_scmi_close(VirtIODevice *vdev); -void virtio_scmi_reset(VirtIODevice *vdev); extern const struct virtio_device_ops virtio_scmi_ops; From eee91280df7367aef2437f60a45e31bd34dde947 Mon Sep 17 00:00:00 2001 From: agicy Date: Wed, 12 Aug 2026 02:57:19 +0000 Subject: [PATCH 5/6] refactor(virtio): const-correct device/config ops boundaries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit const-qualify the read-only data flow across the whole boundary: - config_ops.parse and every device parse_params take const cJSON * (scmi's void *json_array becomes const cJSON *, dropping the casts) - ops->init, create_virtio_device and create_virtio_device_from_json take const void *params / const cJSON *device_json - virtio-net: init_net_dev/open_tap/virtio_net_init take const inputs, so the (uint8_t *)/(char *) casts in net do_init disappear gpu: init_gpu_dev takes const GPURequestedState * and its stale non-static declaration is dropped from virtio_gpu.h — the definition was static since the encapsulation cleanup, so the header decl was both dead and (with VIRTIO_GPU=y) a static-after-extern compile error. --- tools/virtio/devices/blk/virtio_blk.c | 4 ++-- tools/virtio/devices/console/virtio_console.c | 4 ++-- tools/virtio/devices/gpu/virtio_gpu_base.c | 4 ++-- tools/virtio/devices/net/virtio_net.c | 14 +++++++------- tools/virtio/devices/scmi/virtio_scmi.c | 18 +++++++++--------- tools/virtio/include/virtio.h | 8 ++++---- tools/virtio/include/virtio_gpu.h | 8 -------- tools/virtio/include/virtio_scmi.h | 8 ++++---- tools/virtio/virtio.c | 4 ++-- 9 files changed, 32 insertions(+), 40 deletions(-) diff --git a/tools/virtio/devices/blk/virtio_blk.c b/tools/virtio/devices/blk/virtio_blk.c index 8359a3f9..d2c0bcc0 100644 --- a/tools/virtio/devices/blk/virtio_blk.c +++ b/tools/virtio/devices/blk/virtio_blk.c @@ -280,7 +280,7 @@ static void virtio_blk_close(VirtIODevice *vdev) { free(vdev); } -static int virtio_blk_do_init(VirtIODevice *vdev, void *params) { +static int virtio_blk_do_init(VirtIODevice *vdev, const void *params) { const struct virtio_blk_init_params *p = params; if (!p) return -EINVAL; @@ -302,7 +302,7 @@ const struct virtio_device_ops virtio_blk_ops = { .notify_handlers = {virtio_blk_notify_handler}, }; -static int virtio_blk_parse_params(cJSON *json, void **out) { +static int virtio_blk_parse_params(const cJSON *json, void **out) { struct virtio_blk_init_params *p = calloc(1, sizeof(*p)); if (!p) return -ENOMEM; diff --git a/tools/virtio/devices/console/virtio_console.c b/tools/virtio/devices/console/virtio_console.c index a5ad56e1..11e48e18 100644 --- a/tools/virtio/devices/console/virtio_console.c +++ b/tools/virtio/devices/console/virtio_console.c @@ -226,7 +226,7 @@ static void virtio_console_close(VirtIODevice *vdev) { free(vdev); } -static int virtio_console_do_init(VirtIODevice *vdev, void *params) { +static int virtio_console_do_init(VirtIODevice *vdev, const void *params) { (void)params; vdev->dev = init_console_dev(); if (!vdev->dev) @@ -249,7 +249,7 @@ const struct virtio_device_ops virtio_console_ops = { }, }; -static int virtio_console_parse_params(cJSON *json, void **out) { +static int virtio_console_parse_params(const cJSON *json, void **out) { (void)json; *out = NULL; return 0; diff --git a/tools/virtio/devices/gpu/virtio_gpu_base.c b/tools/virtio/devices/gpu/virtio_gpu_base.c index 0e950eee..a3ea1dc5 100644 --- a/tools/virtio/devices/gpu/virtio_gpu_base.c +++ b/tools/virtio/devices/gpu/virtio_gpu_base.c @@ -24,7 +24,7 @@ #include #include -static GPUDev *init_gpu_dev(GPURequestedState *requested_state) { +static GPUDev *init_gpu_dev(const GPURequestedState *requested_state) { log_info("initializing GPUDev"); if (requested_state == NULL) { @@ -255,7 +255,7 @@ static void virtio_gpu_reset(VirtIODevice *vdev) { } } -static int virtio_gpu_do_init(VirtIODevice *vdev, void *params) { +static int virtio_gpu_do_init(VirtIODevice *vdev, const void *params) { vdev->dev = init_gpu_dev(params); if (!vdev->dev) return -ENOMEM; diff --git a/tools/virtio/devices/net/virtio_net.c b/tools/virtio/devices/net/virtio_net.c index d5212f76..dde22f65 100644 --- a/tools/virtio/devices/net/virtio_net.c +++ b/tools/virtio/devices/net/virtio_net.c @@ -24,7 +24,7 @@ #include #include -static NetDev *init_net_dev(uint8_t mac[]) { +static NetDev *init_net_dev(const uint8_t mac[]) { NetDev *dev = malloc(sizeof(NetDev)); dev->config.mac[0] = mac[0]; dev->config.mac[1] = mac[1]; @@ -42,7 +42,7 @@ static NetDev *init_net_dev(uint8_t mac[]) { } // open tap device -static int open_tap(char *devname) { +static int open_tap(const char *devname) { log_info("virtio net tap open"); int tunfd; struct ifreq ifr; @@ -281,7 +281,7 @@ static void net_on_status(VirtIODevice *vdev, uint32_t status) { } } -static int virtio_net_init(VirtIODevice *vdev, char *devname) { +static int virtio_net_init(VirtIODevice *vdev, const char *devname) { log_info("virtio net init"); NetDev *net = vdev->dev; // open tap device @@ -345,14 +345,14 @@ static void virtio_net_close(VirtIODevice *vdev) { free(vdev); } -static int virtio_net_do_init(VirtIODevice *vdev, void *params) { +static int virtio_net_do_init(VirtIODevice *vdev, const void *params) { const struct virtio_net_init_params *p = params; if (!p) return -EINVAL; - vdev->dev = init_net_dev((uint8_t *)p->mac); + vdev->dev = init_net_dev(p->mac); if (!vdev->dev) return -ENOMEM; - return virtio_net_init(vdev, (char *)p->tap); + return virtio_net_init(vdev, p->tap); } const struct virtio_device_ops virtio_net_ops = { @@ -371,7 +371,7 @@ const struct virtio_device_ops virtio_net_ops = { }, }; -static int virtio_net_parse_params(cJSON *json, void **out) { +static int virtio_net_parse_params(const cJSON *json, void **out) { struct virtio_net_init_params *p = calloc(1, sizeof(*p)); if (!p) return -ENOMEM; diff --git a/tools/virtio/devices/scmi/virtio_scmi.c b/tools/virtio/devices/scmi/virtio_scmi.c index bceb5bd9..7d2f7183 100644 --- a/tools/virtio/devices/scmi/virtio_scmi.c +++ b/tools/virtio/devices/scmi/virtio_scmi.c @@ -19,7 +19,7 @@ #include #include -static int parse_id_array(cJSON *json_array, uint32_t **ids_out, +static int parse_id_array(const cJSON *json_array, uint32_t **ids_out, uint32_t *count_out) { if (!json_array || !cJSON_IsArray(json_array)) { *ids_out = NULL; @@ -66,18 +66,18 @@ void scmi_dev_free(SCMIDev *dev) { } int scmi_dev_parse_clock_ids(struct virtio_scmi_init_params *p, - void *json_array) { - return parse_id_array((cJSON *)json_array, &p->clock_ids, &p->clock_count); + const cJSON *json_array) { + return parse_id_array(json_array, &p->clock_ids, &p->clock_count); } int scmi_dev_parse_reset_ids(struct virtio_scmi_init_params *p, - void *json_array) { - return parse_id_array((cJSON *)json_array, &p->reset_ids, &p->reset_count); + const cJSON *json_array) { + return parse_id_array(json_array, &p->reset_ids, &p->reset_count); } int scmi_dev_parse_power_ids(struct virtio_scmi_init_params *p, - void *json_array) { - return parse_id_array((cJSON *)json_array, &p->power_ids, &p->power_count); + const cJSON *json_array) { + return parse_id_array(json_array, &p->power_ids, &p->power_count); } void scmi_dev_free_params(struct virtio_scmi_init_params *p) { @@ -193,7 +193,7 @@ static void virtio_scmi_close(VirtIODevice *vdev) { free(vdev); } -static int virtio_scmi_do_init(VirtIODevice *vdev, void *params) { +static int virtio_scmi_do_init(VirtIODevice *vdev, const void *params) { const struct virtio_scmi_init_params *p = params; SCMIDev *dev; @@ -273,7 +273,7 @@ const struct virtio_device_ops virtio_scmi_ops = { }, }; -static int virtio_scmi_parse_params(cJSON *json, void **out) { +static int virtio_scmi_parse_params(const cJSON *json, void **out) { struct virtio_scmi_init_params *p = calloc(1, sizeof(*p)); if (!p) return -ENOMEM; diff --git a/tools/virtio/include/virtio.h b/tools/virtio/include/virtio.h index 9ef82deb..a6e88dfa 100644 --- a/tools/virtio/include/virtio.h +++ b/tools/virtio/include/virtio.h @@ -136,7 +136,7 @@ struct virtio_device_ops { uint64_t features; uint32_t num_queues; uint32_t queue_max_size; - int (*init)(VirtIODevice *vdev, void *params); + int (*init)(VirtIODevice *vdev, const void *params); void (*close)(VirtIODevice *vdev); void (*reset)(VirtIODevice *vdev); void (*status_changed)(VirtIODevice *vdev, uint32_t status); @@ -145,7 +145,7 @@ struct virtio_device_ops { }; struct virtio_config_ops { - int (*parse)(cJSON *json, void **params_out); + int (*parse)(const cJSON *json, void **params_out); void (*free)(void *params); }; // used event idx for driver telling device when to notify driver. @@ -173,7 +173,7 @@ void rw_barrier(void); VirtIODevice *create_virtio_device(VirtioDeviceType dev_type, uint32_t zone_id, uint64_t base_addr, uint64_t len, - uint32_t irq_id, void *params); + uint32_t irq_id, const void *params); void init_mmio_regs(VirtMmioRegs *regs, VirtioDeviceType type); @@ -256,7 +256,7 @@ void handle_virtio_requests(); int virtio_init(); -int create_virtio_device_from_json(cJSON *device_json, int zone_id); +int create_virtio_device_from_json(const cJSON *device_json, int zone_id); int virtio_start_from_json(char *json_path); diff --git a/tools/virtio/include/virtio_gpu.h b/tools/virtio/include/virtio_gpu.h index fd69590c..32a4f2a7 100644 --- a/tools/virtio/include/virtio_gpu.h +++ b/tools/virtio/include/virtio_gpu.h @@ -212,14 +212,6 @@ typedef struct virtio_gpu_control_cmd { /********************************************************************* virtio_gpu_base.c */ -// Initialize GPUDev structure -GPUDev *init_gpu_dev(GPURequestedState *requested_states); - -// Initialize virtio-gpu device - -// Close virtio-gpu device - -// Reset virtio-gpu device extern const struct virtio_device_ops virtio_gpu_ops; extern const struct virtio_config_ops virtio_gpu_config_ops; diff --git a/tools/virtio/include/virtio_scmi.h b/tools/virtio/include/virtio_scmi.h index 0486e5eb..8ef73653 100644 --- a/tools/virtio/include/virtio_scmi.h +++ b/tools/virtio/include/virtio_scmi.h @@ -249,13 +249,13 @@ void scmi_dev_free(SCMIDev *dev); extern const struct virtio_device_ops virtio_scmi_ops; -/* JSON array parsing: fills dev->clock_ids / dev->reset_ids / dev->power_ids */ +/* JSON array parsing: fills p->clock_ids / p->reset_ids / p->power_ids */ int scmi_dev_parse_clock_ids(struct virtio_scmi_init_params *p, - void *json_array); + const cJSON *json_array); int scmi_dev_parse_reset_ids(struct virtio_scmi_init_params *p, - void *json_array); + const cJSON *json_array); int scmi_dev_parse_power_ids(struct virtio_scmi_init_params *p, - void *json_array); + const cJSON *json_array); void scmi_dev_free_params(struct virtio_scmi_init_params *p); /* /dev/hvisor fd, opened once in virtio_start() */ diff --git a/tools/virtio/virtio.c b/tools/virtio/virtio.c index e6535e77..2d3cc4e0 100644 --- a/tools/virtio/virtio.c +++ b/tools/virtio/virtio.c @@ -229,7 +229,7 @@ static int init_virtio_queue(VirtIODevice *vdev, // create a virtio device. VirtIODevice *create_virtio_device(VirtioDeviceType dev_type, uint32_t zone_id, uint64_t base_addr, uint64_t len, - uint32_t irq_id, void *params) { + uint32_t irq_id, const void *params) { const struct virtio_device_ops *ops = lookup_ops(dev_type); if (!ops) { log_error("unsupported virtio device type %d", dev_type); @@ -1498,7 +1498,7 @@ int virtio_init() { return -1; } -int create_virtio_device_from_json(cJSON *device_json, int zone_id) { +int create_virtio_device_from_json(const cJSON *device_json, int zone_id) { char *status = SAFE_CJSON_GET_OBJECT_ITEM(device_json, "status")->valuestring; if (strcmp(status, "disable") == 0) From fe6e75f930e7b3d8b9fceb87188dd78ebd68ef9d Mon Sep 17 00:00:00 2001 From: agicy Date: Wed, 12 Aug 2026 03:17:21 +0000 Subject: [PATCH 6/6] refactor(virtio): simplify device init paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unify the device-init failure contract across all devices: init attaches resources to dev as they are created and returns on any failure — ops->close on the create error path then cleans up whatever is attached (each close guards its fds and frees NULL-safe). - virtio-net: replace the byte-wise MAC copy in init_net_dev with a single memcpy. Drop the manual close/tapfd=-1 and free/in_iov=NULL bookkeeping on the set_nonblocking/add_event/iov failure paths — close() owns all of it. set_nonblocking failure now returns directly instead of proceeding to a pointless add_event(-1). - virtio-blk: attach img_fd to dev->img_fd right after open() so any later failure is cleaned up by ops->close; drop the redundant close(-1) on open failure and the manual close on fstat failure. - virtio-console: drop the manual close/state-reset bookkeeping on the slave_fd/set_nonblocking/add_event failure paths — close() owns master_fd, slave_keepalive_fd and event. - virtio-scmi: adopt the device-init contract — init attaches the (possibly partially built) dev to vdev->dev before any failure point, and the create error path runs ops->close, which is safe on any partial state (scmi_dev_free tolerates NULL id arrays, close skips a NULL dev). This removes the err_copy label and the manual frees from virtio_scmi_do_init; cleanup logic now lives in exactly one place. The three id arrays (clock/reset/power) were copied with the same calloc-check-memcpy block; extract scmi_copy_id_array() so the body shrinks to a 3-way helper call. Failure contract unchanged. --- tools/virtio/devices/blk/virtio_blk.c | 24 +++++---- tools/virtio/devices/console/virtio_console.c | 17 +----- tools/virtio/devices/net/virtio_net.c | 20 ++----- tools/virtio/devices/scmi/virtio_scmi.c | 53 ++++++++----------- tools/virtio/event_monitor.c | 22 +++++++- tools/virtio/include/event_monitor.h | 1 + 6 files changed, 63 insertions(+), 74 deletions(-) diff --git a/tools/virtio/devices/blk/virtio_blk.c b/tools/virtio/devices/blk/virtio_blk.c index d2c0bcc0..9c04b695 100644 --- a/tools/virtio/devices/blk/virtio_blk.c +++ b/tools/virtio/devices/blk/virtio_blk.c @@ -13,6 +13,7 @@ #include "virtio.h" #include #include +#include #include #include #include @@ -146,25 +147,28 @@ static BlkDev *init_blk_dev(VirtIODevice *vdev) { } static int virtio_blk_init(VirtIODevice *vdev, const char *img_path) { - int img_fd = open(img_path, O_RDWR); BlkDev *dev = vdev->dev; - struct stat st; - uint64_t blk_size; - if (img_fd == -1) { + if (!dev) { + log_error("virtio_blk_init: vdev->dev is nullptr"); + return -1; + } + + dev->img_fd = open(img_path, O_RDWR); + if (dev->img_fd == -1) { log_error("cannot open %s, Error code is %d", img_path, errno); - close(img_fd); return -1; } - if (fstat(img_fd, &st) == -1) { + + struct stat st; + if (fstat(dev->img_fd, &st) == -1) { log_error("cannot stat %s, Error code is %d", img_path, errno); - close(img_fd); return -1; } - blk_size = st.st_size / 512; // 512 bytes per block + uint64_t blk_size = st.st_size / SECTOR_BSIZE; dev->config.capacity = blk_size; dev->config.size_max = blk_size; - dev->img_fd = img_fd; - log_info("debug: virtio_blk_init: %s, size is %lld", img_path, + + log_info("virtio_blk_init: %s, size is %" PRIu64, img_path, dev->config.capacity); return 0; } diff --git a/tools/virtio/devices/console/virtio_console.c b/tools/virtio/devices/console/virtio_console.c index 11e48e18..a6390d22 100644 --- a/tools/virtio/devices/console/virtio_console.c +++ b/tools/virtio/devices/console/virtio_console.c @@ -115,8 +115,6 @@ static int virtio_console_init(VirtIODevice *vdev) { slave_fd = open(slave_name, O_RDWR); if (slave_fd < 0) { log_error("Failed to open slave pty, errno is %d", errno); - close(master_fd); - dev->master_fd = -1; return -1; } @@ -129,13 +127,7 @@ static int virtio_console_init(VirtIODevice *vdev) { dev->slave_keepalive_fd = slave_fd; if (set_nonblocking(dev->master_fd) < 0) { - close(dev->master_fd); - if (dev->slave_keepalive_fd >= 0) { - close(dev->slave_keepalive_fd); - dev->slave_keepalive_fd = -1; - } - dev->master_fd = -1; - log_error("Failed to set nonblocking mode, fd closed!"); + log_error("Failed to set nonblocking mode"); return -1; } @@ -144,12 +136,6 @@ static int virtio_console_init(VirtIODevice *vdev) { if (dev->event == NULL) { log_error("Can't register console event"); - close(master_fd); - if (dev->slave_keepalive_fd >= 0) { - close(dev->slave_keepalive_fd); - dev->slave_keepalive_fd = -1; - } - dev->master_fd = -1; return -1; } @@ -217,6 +203,7 @@ static void virtio_console_close(VirtIODevice *vdev) { close(dev->master_fd); if (dev->slave_keepalive_fd >= 0) close(dev->slave_keepalive_fd); + remove_event(dev->event); free(dev->event); free(dev); vdev->dev = NULL; diff --git a/tools/virtio/devices/net/virtio_net.c b/tools/virtio/devices/net/virtio_net.c index dde22f65..db4d7be1 100644 --- a/tools/virtio/devices/net/virtio_net.c +++ b/tools/virtio/devices/net/virtio_net.c @@ -26,12 +26,7 @@ static NetDev *init_net_dev(const uint8_t mac[]) { NetDev *dev = malloc(sizeof(NetDev)); - dev->config.mac[0] = mac[0]; - dev->config.mac[1] = mac[1]; - dev->config.mac[2] = mac[2]; - dev->config.mac[3] = mac[3]; - dev->config.mac[4] = mac[4]; - dev->config.mac[5] = mac[5]; + memcpy(dev->config.mac, mac, sizeof(dev->config.mac)); dev->config.status = VIRTIO_NET_S_LINK_UP; dev->tapfd = -1; dev->rx_ready = 0; @@ -293,27 +288,19 @@ static int virtio_net_init(VirtIODevice *vdev, const char *devname) { // set tap device O_NONBLOCK. If io operation like readv blocks, then return // errno EWOULDBLOCK if (set_nonblocking(net->tapfd) < 0) { - close(net->tapfd); - net->tapfd = -1; + log_error("failed to set tap nonblocking"); + return -1; } // register an epoll read event for tap device net->event = add_event(net->tapfd, EPOLLIN, virtio_net_event_handler, vdev); if (net->event == NULL) { log_error("Can't register net event"); - close(net->tapfd); - net->tapfd = -1; return -1; } net->in_iov = malloc(sizeof(struct iovec) * NET_IOV_MAX); net->out_iov = malloc(sizeof(struct iovec) * NET_IOV_MAX); if (!net->in_iov || !net->out_iov) { log_error("failed to allocate iov buffers"); - free(net->in_iov); - free(net->out_iov); - net->in_iov = NULL; - net->out_iov = NULL; - close(net->tapfd); - net->tapfd = -1; return -1; } return 0; @@ -334,6 +321,7 @@ static void virtio_net_close(VirtIODevice *vdev) { if (dev) { if (dev->tapfd >= 0) close(dev->tapfd); + remove_event(dev->event); free(dev->event); free(dev->in_iov); free(dev->out_iov); diff --git a/tools/virtio/devices/scmi/virtio_scmi.c b/tools/virtio/devices/scmi/virtio_scmi.c index 7d2f7183..3a9a6dec 100644 --- a/tools/virtio/devices/scmi/virtio_scmi.c +++ b/tools/virtio/devices/scmi/virtio_scmi.c @@ -193,6 +193,22 @@ static void virtio_scmi_close(VirtIODevice *vdev) { free(vdev); } +/* + * Deep-copy a count-sized uint32 id array; count == 0 keeps *dst NULL. + * Failure cleanup is deferred to ops->close (scmi_dev_free tolerates + * NULL id arrays), so a non-zero return just needs to propagate. + */ +static int scmi_copy_id_array(uint32_t **dst, const uint32_t *src, + uint32_t count) { + if (count == 0) + return 0; + *dst = calloc(count, sizeof(uint32_t)); + if (!*dst) + return -ENOMEM; + memcpy(*dst, src, count * sizeof(uint32_t)); + return 0; +} + static int virtio_scmi_do_init(VirtIODevice *vdev, const void *params) { const struct virtio_scmi_init_params *p = params; SCMIDev *dev; @@ -201,34 +217,16 @@ static int virtio_scmi_do_init(VirtIODevice *vdev, const void *params) { dev = calloc(1, sizeof(SCMIDev)); if (!dev) return -ENOMEM; + vdev->dev = dev; // Deep-copy id arrays so that SCMIDev and the caller each own their // copies — no ownership transfer, no double-free risk. - if (p->clock_count > 0) { - dev->clock_ids = calloc(p->clock_count, sizeof(uint32_t)); - if (!dev->clock_ids) - goto err_copy; - memcpy(dev->clock_ids, p->clock_ids, - p->clock_count * sizeof(uint32_t)); - } + if (scmi_copy_id_array(&dev->clock_ids, p->clock_ids, p->clock_count) || + scmi_copy_id_array(&dev->reset_ids, p->reset_ids, p->reset_count) || + scmi_copy_id_array(&dev->power_ids, p->power_ids, p->power_count)) + return -ENOMEM; dev->clock_count = p->clock_count; - - if (p->reset_count > 0) { - dev->reset_ids = calloc(p->reset_count, sizeof(uint32_t)); - if (!dev->reset_ids) - goto err_copy; - memcpy(dev->reset_ids, p->reset_ids, - p->reset_count * sizeof(uint32_t)); - } dev->reset_count = p->reset_count; - - if (p->power_count > 0) { - dev->power_ids = calloc(p->power_count, sizeof(uint32_t)); - if (!dev->power_ids) - goto err_copy; - memcpy(dev->power_ids, p->power_ids, - p->power_count * sizeof(uint32_t)); - } dev->power_count = p->power_count; scmi_dev_register_protocol(dev, SCMI_PROTO_ID_BASE, @@ -246,17 +244,10 @@ static int virtio_scmi_do_init(VirtIODevice *vdev, const void *params) { dev = scmi_dev_create(); if (!dev) return -ENOMEM; + vdev->dev = dev; } - vdev->dev = dev; return 0; - -err_copy: - free(dev->clock_ids); - free(dev->reset_ids); - free(dev->power_ids); - free(dev); - return -ENOMEM; } const struct virtio_device_ops virtio_scmi_ops = { diff --git a/tools/virtio/event_monitor.c b/tools/virtio/event_monitor.c index 7c7c0b48..095b652a 100644 --- a/tools/virtio/event_monitor.c +++ b/tools/virtio/event_monitor.c @@ -118,10 +118,28 @@ int initialize_event_monitor() { } } +void remove_event(struct hvisor_event *hevent) { + int i; + + if (!hevent) + return; + + for (i = 0; i < events_num; i++) { + if (events[i] == hevent) { + epoll_ctl(epoll_fd, EPOLL_CTL_DEL, hevent->fd, NULL); + events[i] = NULL; + return; + } + } +} + void destroy_event_monitor() { int i; - for (i = 0; i < events_num; i++) - epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i]->fd, NULL); + for (i = 0; i < events_num; i++) { + if (events[i] != NULL) + epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i]->fd, NULL); + events[i] = NULL; + } close(epoll_fd); // When the main thread exits, the epoll thread will also exit. Therefore, // we do not directly terminate the epoll thread here. diff --git a/tools/virtio/include/event_monitor.h b/tools/virtio/include/event_monitor.h index 55b27396..742028bd 100644 --- a/tools/virtio/include/event_monitor.h +++ b/tools/virtio/include/event_monitor.h @@ -23,4 +23,5 @@ int initialize_event_monitor(void); void destroy_event_monitor(); struct hvisor_event *add_event(int fd, int epoll_type, void (*handler)(int, int, void *), void *param); +void remove_event(struct hvisor_event *hevent); #endif // HVISOR_EVENT_H