1*7ccb23ddSdv /* $OpenBSD: virtio.h,v 1.53 2025/01/08 15:46:10 dv Exp $ */ 215caf263Sreyk 3f3c0184aSmlarkin /* 4f3c0184aSmlarkin * Copyright (c) 2015 Mike Larkin <mlarkin@openbsd.org> 5f3c0184aSmlarkin * 6f3c0184aSmlarkin * Permission to use, copy, modify, and distribute this software for any 7f3c0184aSmlarkin * purpose with or without fee is hereby granted, provided that the above 8f3c0184aSmlarkin * copyright notice and this permission notice appear in all copies. 9f3c0184aSmlarkin * 10f3c0184aSmlarkin * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11f3c0184aSmlarkin * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12f3c0184aSmlarkin * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13f3c0184aSmlarkin * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14f3c0184aSmlarkin * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15f3c0184aSmlarkin * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16f3c0184aSmlarkin * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17f3c0184aSmlarkin */ 18f3c0184aSmlarkin 196eb4c859Sdv #include <sys/types.h> 206eb4c859Sdv 21d7f9c71cSmlarkin #include <dev/pv/virtioreg.h> 226c31e103Sdv #include <net/if_tun.h> 23f3c0184aSmlarkin 246eb4c859Sdv #include <event.h> 256eb4c859Sdv 266eb4c859Sdv #include "vmd.h" 276eb4c859Sdv 286eb4c859Sdv #ifndef _VIRTIO_H_ 296eb4c859Sdv #define _VIRTIO_H_ 306eb4c859Sdv 31f3c0184aSmlarkin #define VIRTQUEUE_ALIGN(n) (((n)+(VIRTIO_PAGE_SIZE-1))& \ 32f3c0184aSmlarkin ~(VIRTIO_PAGE_SIZE-1)) 3362df93eeSreyk #define ALIGNSZ(sz, align) ((sz + align - 1) & ~(align - 1)) 3462df93eeSreyk #define MIN(a,b) (((a)<(b))?(a):(b)) 35f3c0184aSmlarkin 3620e554f8Sdv /* Queue sizes must be power of two and less than IOV_MAX (1024). */ 37f3c0184aSmlarkin #define VIORND_QUEUE_SIZE 64 38f3c0184aSmlarkin #define VIORND_QUEUE_MASK (VIORND_QUEUE_SIZE - 1) 39f3c0184aSmlarkin 40f4229d5cSmlarkin #define VIOBLK_QUEUE_SIZE 128 41f3c0184aSmlarkin #define VIOBLK_QUEUE_MASK (VIOBLK_QUEUE_SIZE - 1) 4220e554f8Sdv #define VIOBLK_SEG_MAX (VIOBLK_QUEUE_SIZE - 2) 43f3c0184aSmlarkin 4495ab188fSccardenas #define VIOSCSI_QUEUE_SIZE 128 4595ab188fSccardenas #define VIOSCSI_QUEUE_MASK (VIOSCSI_QUEUE_SIZE - 1) 4695ab188fSccardenas 479e230518Smlarkin #define VIONET_QUEUE_SIZE 256 48f3c0184aSmlarkin #define VIONET_QUEUE_MASK (VIONET_QUEUE_SIZE - 1) 49f3c0184aSmlarkin 506c31e103Sdv /* Virtio network device is backed by tap(4), so inherit limits */ 516c31e103Sdv #define VIONET_HARD_MTU TUNMRU 526c31e103Sdv #define VIONET_MIN_TXLEN ETHER_HDR_LEN 536c31e103Sdv #define VIONET_MAX_TXLEN VIONET_HARD_MTU + ETHER_HDR_LEN 546c31e103Sdv 553320a88dSreyk /* VMM Control Interface shutdown timeout (in seconds) */ 56*7ccb23ddSdv #define VMMCI_TIMEOUT_SHORT 3 57*7ccb23ddSdv #define VMMCI_TIMEOUT_LONG 120 58f84d5d33Sreyk 5995ab188fSccardenas /* All the devices we support have either 1, 2 or 3 queues */ 6095ab188fSccardenas /* viornd - 1 queue 6195ab188fSccardenas * vioblk - 1 queue 6295ab188fSccardenas * vionet - 2 queues 6395ab188fSccardenas * vioscsi - 3 queues 6495ab188fSccardenas */ 6595ab188fSccardenas #define VIRTIO_MAX_QUEUES 3 66f3c0184aSmlarkin 673481ecdfSdv #define MAXPHYS (64 * 1024) /* max raw I/O transfer size */ 683481ecdfSdv 69e44e0427Sstefan /* 700bd10b9fSdv * Rename the address config register to be more descriptive. 710bd10b9fSdv */ 720bd10b9fSdv #define VIRTIO_CONFIG_QUEUE_PFN VIRTIO_CONFIG_QUEUE_ADDRESS 7320e554f8Sdv #define DEVICE_NEEDS_RESET VIRTIO_CONFIG_DEVICE_STATUS_DEVICE_NEEDS_RESET 7420e554f8Sdv #define DESC_WRITABLE(/* struct vring_desc */ x) \ 7520e554f8Sdv (((x)->flags & VRING_DESC_F_WRITE) ? 1 : 0) 7620e554f8Sdv 770bd10b9fSdv 780bd10b9fSdv /* 793481ecdfSdv * VM <-> Device messaging. 803481ecdfSdv */ 813481ecdfSdv struct viodev_msg { 823481ecdfSdv uint8_t type; 833481ecdfSdv #define VIODEV_MSG_INVALID 0 843481ecdfSdv #define VIODEV_MSG_READY 1 853481ecdfSdv #define VIODEV_MSG_ERROR 2 863481ecdfSdv #define VIODEV_MSG_KICK 3 873481ecdfSdv #define VIODEV_MSG_IO_READ 4 883481ecdfSdv #define VIODEV_MSG_IO_WRITE 5 893481ecdfSdv #define VIODEV_MSG_DUMP 6 903481ecdfSdv #define VIODEV_MSG_SHUTDOWN 7 913481ecdfSdv 923481ecdfSdv uint16_t reg; /* VirtIO register */ 933481ecdfSdv uint8_t io_sz; /* IO instruction size */ 943481ecdfSdv uint8_t vcpu; /* VCPU id */ 953481ecdfSdv uint8_t irq; /* IRQ number */ 963481ecdfSdv 973481ecdfSdv int8_t state; /* Interrupt state toggle (if any) */ 983481ecdfSdv #define INTR_STATE_ASSERT 1 993481ecdfSdv #define INTR_STATE_NOOP 0 1003481ecdfSdv #define INTR_STATE_DEASSERT -1 1013481ecdfSdv 1023481ecdfSdv uint32_t data; /* Data (if any) */ 1033481ecdfSdv uint8_t data_valid; /* 1 if data field is populated. */ 1043481ecdfSdv } __packed; 1053481ecdfSdv 1063481ecdfSdv /* 107e44e0427Sstefan * This struct stores notifications from a virtio driver. There is 108e44e0427Sstefan * one such struct per virtio device. 109e44e0427Sstefan */ 110f3c0184aSmlarkin struct virtio_io_cfg { 111f3c0184aSmlarkin uint32_t device_feature; 112f3c0184aSmlarkin uint32_t guest_feature; 1130bd10b9fSdv uint32_t queue_pfn; 114f3c0184aSmlarkin uint16_t queue_size; 115f3c0184aSmlarkin uint16_t queue_select; 116f3c0184aSmlarkin uint16_t queue_notify; 117f3c0184aSmlarkin uint8_t device_status; 118f3c0184aSmlarkin uint8_t isr_status; 119f3c0184aSmlarkin }; 120f3c0184aSmlarkin 1219617633bSccardenas struct virtio_backing { 1229617633bSccardenas void *p; 12320e554f8Sdv ssize_t (*pread)(void *, char *, size_t, off_t); 12420e554f8Sdv ssize_t (*preadv)(void *, struct iovec *, int, off_t); 12520e554f8Sdv ssize_t (*pwrite)(void *, char *, size_t, off_t); 12620e554f8Sdv ssize_t (*pwritev)(void *, struct iovec *, int, off_t); 12720e554f8Sdv void (*close)(void *, int); 1289617633bSccardenas }; 1299617633bSccardenas 130e44e0427Sstefan /* 131e44e0427Sstefan * A virtio device can have several virtqs. For example, vionet has one virtq 132e44e0427Sstefan * each for transmitting and receiving packets. This struct describes the state 133e44e0427Sstefan * of one virtq, such as their address in memory, size, offsets of rings, etc. 134e44e0427Sstefan * There is one virtio_vq_info per virtq. 135e44e0427Sstefan */ 136f3c0184aSmlarkin struct virtio_vq_info { 137e44e0427Sstefan /* Guest physical address of virtq */ 1380bd10b9fSdv uint64_t q_gpa; 1390bd10b9fSdv 1400bd10b9fSdv /* Host virtual address of virtq */ 1410bd10b9fSdv void *q_hva; 142e44e0427Sstefan 143e44e0427Sstefan /* Queue size: number of queue entries in virtq */ 144f3c0184aSmlarkin uint32_t qs; 145e44e0427Sstefan 146e44e0427Sstefan /* 147e44e0427Sstefan * The offset of the 'available' ring within the virtq located at 148e44e0427Sstefan * guest physical address qa above 149e44e0427Sstefan */ 150f3c0184aSmlarkin uint32_t vq_availoffset; 151e44e0427Sstefan 152e44e0427Sstefan /* 153e44e0427Sstefan * The offset of the 'used' ring within the virtq located at guest 154e44e0427Sstefan * physical address qa above 155e44e0427Sstefan */ 156f3c0184aSmlarkin uint32_t vq_usedoffset; 157e44e0427Sstefan 158e44e0427Sstefan /* 159e44e0427Sstefan * The index into a slot of the 'available' ring that a virtio device 160e44e0427Sstefan * can consume next 161e44e0427Sstefan */ 162f3c0184aSmlarkin uint16_t last_avail; 163e44e0427Sstefan 164e44e0427Sstefan /* 165e44e0427Sstefan * The most recent index into the 'available' ring that a virtio 166e44e0427Sstefan * driver notified to the host. 167e44e0427Sstefan */ 168e44e0427Sstefan uint16_t notified_avail; 169f3c0184aSmlarkin }; 170f3c0184aSmlarkin 17128705897Sccardenas /* 17228705897Sccardenas * Each virtio driver has a notifyq method where one or more messages 17328705897Sccardenas * are ready to be processed on a given virtq. As such, various 17428705897Sccardenas * pieces of information are needed to provide ring accounting while 17528705897Sccardenas * processing a given message such as virtq indexes, vring pointers, and 17628705897Sccardenas * vring descriptors. 17728705897Sccardenas */ 17828705897Sccardenas struct virtio_vq_acct { 17928705897Sccardenas 18028705897Sccardenas /* index of previous avail vring message */ 18128705897Sccardenas uint16_t idx; 18228705897Sccardenas 18328705897Sccardenas /* index of current message containing the request */ 18428705897Sccardenas uint16_t req_idx; 18528705897Sccardenas 18628705897Sccardenas /* index of current message containing the response */ 18728705897Sccardenas uint16_t resp_idx; 18828705897Sccardenas 18928705897Sccardenas /* vring descriptor pointer */ 19028705897Sccardenas struct vring_desc *desc; 19128705897Sccardenas 19228705897Sccardenas /* vring descriptor pointer for request header and data */ 19328705897Sccardenas struct vring_desc *req_desc; 19428705897Sccardenas 19528705897Sccardenas /* vring descriptor pointer for response header and data */ 19628705897Sccardenas struct vring_desc *resp_desc; 19728705897Sccardenas 19828705897Sccardenas /* pointer to the available vring */ 19928705897Sccardenas struct vring_avail *avail; 20028705897Sccardenas 20128705897Sccardenas /* pointer to the used vring */ 20228705897Sccardenas struct vring_used *used; 20328705897Sccardenas }; 20428705897Sccardenas 205f3c0184aSmlarkin struct viornd_dev { 206f3c0184aSmlarkin struct virtio_io_cfg cfg; 207f3c0184aSmlarkin 208f3c0184aSmlarkin struct virtio_vq_info vq[VIRTIO_MAX_QUEUES]; 209813e3047Spd 210813e3047Spd uint8_t pci_id; 2117b7c4b51Smlarkin int irq; 2127b7c4b51Smlarkin uint32_t vm_id; 213f3c0184aSmlarkin }; 214f3c0184aSmlarkin 215f3c0184aSmlarkin struct vioblk_dev { 216f3c0184aSmlarkin struct virtio_io_cfg cfg; 217f3c0184aSmlarkin struct virtio_vq_info vq[VIRTIO_MAX_QUEUES]; 2189617633bSccardenas struct virtio_backing file; 219f3c0184aSmlarkin 2203481ecdfSdv int disk_fd[VM_MAX_BASE_PER_DISK]; /* fds for disk image(s) */ 2213481ecdfSdv uint8_t ndisk_fd; /* number of valid disk fds */ 22220e554f8Sdv uint64_t capacity; /* size in 512 byte sectors */ 22320e554f8Sdv uint32_t seg_max; /* maximum number of segments */ 224813e3047Spd 2253481ecdfSdv unsigned int idx; 226f3c0184aSmlarkin }; 227f3c0184aSmlarkin 22895ab188fSccardenas /* vioscsi will use at least 3 queues - 5.6.2 Virtqueues 22995ab188fSccardenas * Current implementation will use 3 23095ab188fSccardenas * 0 - control 23195ab188fSccardenas * 1 - event 23295ab188fSccardenas * 2 - requests 23395ab188fSccardenas */ 23495ab188fSccardenas struct vioscsi_dev { 23595ab188fSccardenas struct virtio_io_cfg cfg; 23695ab188fSccardenas 23795ab188fSccardenas struct virtio_vq_info vq[VIRTIO_MAX_QUEUES]; 23895ab188fSccardenas 2399617633bSccardenas struct virtio_backing file; 2409617633bSccardenas 24195ab188fSccardenas /* is the device locked */ 24295ab188fSccardenas int locked; 24395ab188fSccardenas /* size of iso file in bytes */ 24495ab188fSccardenas uint64_t sz; 24595ab188fSccardenas /* last block address read */ 24695ab188fSccardenas uint64_t lba; 24795ab188fSccardenas /* number of blocks represented in iso */ 24895ab188fSccardenas uint64_t n_blocks; 24995ab188fSccardenas uint32_t max_xfer; 25095ab188fSccardenas 25195ab188fSccardenas uint8_t pci_id; 2527b7c4b51Smlarkin uint32_t vm_id; 2537b7c4b51Smlarkin int irq; 25495ab188fSccardenas }; 25595ab188fSccardenas 256f3c0184aSmlarkin struct vionet_dev { 257f3c0184aSmlarkin struct virtio_io_cfg cfg; 258f3c0184aSmlarkin struct virtio_vq_info vq[VIRTIO_MAX_QUEUES]; 259f3c0184aSmlarkin 2603481ecdfSdv int data_fd; /* fd for our tap device */ 2613481ecdfSdv 262f3c0184aSmlarkin uint8_t mac[6]; 26397f33f1dSdv uint8_t hostmac[6]; 2642b2a5f0dSreyk int lockedmac; 265470adcf5Sreyk int local; 266cc104512Sclaudio int pxeboot; 2672272e586Sdv struct local_prefix local_prefix; 268813e3047Spd 2693481ecdfSdv unsigned int idx; 2703481ecdfSdv }; 2713481ecdfSdv 2723481ecdfSdv struct virtio_dev { 2733481ecdfSdv union { 2743481ecdfSdv struct vioblk_dev vioblk; 2753481ecdfSdv struct vionet_dev vionet; 2763481ecdfSdv }; 2773481ecdfSdv 2783481ecdfSdv struct imsgev async_iev; 2793481ecdfSdv struct imsgev sync_iev; 2803481ecdfSdv 2813481ecdfSdv int sync_fd; /* fd for synchronous channel */ 2823481ecdfSdv int async_fd; /* fd for async channel */ 2833481ecdfSdv 284813e3047Spd uint8_t pci_id; 2853481ecdfSdv uint32_t vm_id; 2863481ecdfSdv uint32_t vm_vmid; 2873481ecdfSdv int irq; 2883481ecdfSdv 2893481ecdfSdv pid_t dev_pid; 2903481ecdfSdv char dev_type; 2913481ecdfSdv SLIST_ENTRY(virtio_dev) dev_next; 292f3c0184aSmlarkin }; 293f3c0184aSmlarkin 294f3c0184aSmlarkin struct virtio_net_hdr { 295f3c0184aSmlarkin uint8_t flags; 296f3c0184aSmlarkin uint8_t gso_type; 297f3c0184aSmlarkin uint16_t hdr_len; 298f3c0184aSmlarkin uint16_t gso_size; 299f3c0184aSmlarkin uint16_t csum_start; 300f3c0184aSmlarkin uint16_t csum_offset; 301f3c0184aSmlarkin 302f3c0184aSmlarkin /* 303f3c0184aSmlarkin * num_buffers is only used if VIRTIO_NET_F_MRG_RXBUF is negotiated. 304f3c0184aSmlarkin * vmd(8) doesn't negotiate that, but the field is listed here 305f3c0184aSmlarkin * for completeness sake. 306f3c0184aSmlarkin */ 307f3c0184aSmlarkin /* uint16_t num_buffers; */ 308f3c0184aSmlarkin }; 309f3c0184aSmlarkin 310f84d5d33Sreyk enum vmmci_cmd { 311f84d5d33Sreyk VMMCI_NONE = 0, 312f84d5d33Sreyk VMMCI_SHUTDOWN, 313f84d5d33Sreyk VMMCI_REBOOT, 314e82d5294Smlarkin VMMCI_SYNCRTC, 315f84d5d33Sreyk }; 316f84d5d33Sreyk 317f84d5d33Sreyk struct vmmci_dev { 318f84d5d33Sreyk struct virtio_io_cfg cfg; 3193320a88dSreyk struct event timeout; 320981cad08Sreyk struct timeval time; 321f84d5d33Sreyk enum vmmci_cmd cmd; 322f84d5d33Sreyk uint32_t vm_id; 323f84d5d33Sreyk int irq; 324813e3047Spd uint8_t pci_id; 325*7ccb23ddSdv 326*7ccb23ddSdv pthread_mutex_t mutex; 327*7ccb23ddSdv struct vm_dev_pipe dev_pipe; 328f84d5d33Sreyk }; 329f3c0184aSmlarkin 33020e554f8Sdv /* XXX to be removed once vioscsi is adapted to vectorized io. */ 33195ab188fSccardenas struct ioinfo { 33295ab188fSccardenas uint8_t *buf; 33395ab188fSccardenas ssize_t len; 33495ab188fSccardenas off_t offset; 33595ab188fSccardenas }; 33695ab188fSccardenas 337470adcf5Sreyk /* virtio.c */ 33873613953Sreyk void virtio_init(struct vmd_vm *, int, int[][VM_MAX_BASE_PER_DISK], int *); 33908d0da61Sdv void virtio_broadcast_imsg(struct vmd_vm *, uint16_t, void *, uint16_t); 34073a98491Sdv void virtio_stop(struct vmd_vm *); 34173a98491Sdv void virtio_start(struct vmd_vm *); 34250bebf2cSccardenas void virtio_shutdown(struct vmd_vm *); 343149417b6Sreyk int virtio_dump(int); 34473a98491Sdv int virtio_restore(int, struct vmd_vm *, int, int[][VM_MAX_BASE_PER_DISK], 34573a98491Sdv int *); 3463481ecdfSdv const char *virtio_reg_name(uint8_t); 347f3c0184aSmlarkin uint32_t vring_size(uint32_t); 348a246f7a0Sdv int vm_device_pipe(struct virtio_dev *, void (*)(int, short, void *), 349a246f7a0Sdv struct event_base *); 3503481ecdfSdv int virtio_pci_io(int, uint16_t, uint32_t *, uint8_t *, void *, uint8_t); 351c4fd4c5bSdv void virtio_assert_irq(struct virtio_dev *, int); 352c4fd4c5bSdv void virtio_deassert_irq(struct virtio_dev *, int); 353f3c0184aSmlarkin 354eef1411cSmlarkin int virtio_rnd_io(int, uint16_t, uint32_t *, uint8_t *, void *, uint8_t); 355149417b6Sreyk int viornd_dump(int); 35673a98491Sdv int viornd_restore(int, struct vmd_vm *); 357f3c0184aSmlarkin void viornd_update_qs(void); 358f3c0184aSmlarkin void viornd_update_qa(void); 359f3c0184aSmlarkin int viornd_notifyq(void); 360f3c0184aSmlarkin 3614d2a1fb2Sreyk ssize_t virtio_qcow2_get_base(int, char *, size_t, const char *); 362ead1b146Sdv int virtio_qcow2_create(const char *, const char *, uint64_t); 36362df93eeSreyk int virtio_qcow2_init(struct virtio_backing *, off_t *, int*, size_t); 364ead1b146Sdv int virtio_raw_create(const char *, uint64_t); 36562df93eeSreyk int virtio_raw_init(struct virtio_backing *, off_t *, int*, size_t); 3669617633bSccardenas 367149417b6Sreyk int vioblk_dump(int); 36873a98491Sdv int vioblk_restore(int, struct vmd_vm *, int[][VM_MAX_BASE_PER_DISK]); 369f3c0184aSmlarkin 370149417b6Sreyk int vionet_dump(int); 371149417b6Sreyk int vionet_restore(int, struct vmd_vm *, int *); 37297f33f1dSdv void vionet_set_hostmac(struct vmd_vm *, unsigned int, uint8_t *); 373f3c0184aSmlarkin 374eef1411cSmlarkin int vmmci_io(int, uint16_t, uint32_t *, uint8_t *, void *, uint8_t); 375149417b6Sreyk int vmmci_dump(int); 376149417b6Sreyk int vmmci_restore(int, uint32_t); 377f84d5d33Sreyk int vmmci_ctl(unsigned int); 3783320a88dSreyk void vmmci_ack(unsigned int); 3793320a88dSreyk void vmmci_timeout(int, short, void *); 380f84d5d33Sreyk 381f3c0184aSmlarkin const char *vioblk_cmd_name(uint32_t); 38295ab188fSccardenas int vioscsi_dump(int); 38373a98491Sdv int vioscsi_restore(int, struct vmd_vm *, int); 384470adcf5Sreyk 385470adcf5Sreyk /* dhcp.c */ 3863481ecdfSdv ssize_t dhcp_request(struct virtio_dev *, char *, size_t, char **); 38795ab188fSccardenas 38895ab188fSccardenas /* vioscsi.c */ 38995ab188fSccardenas int vioscsi_io(int, uint16_t, uint32_t *, uint8_t *, void *, uint8_t); 39095ab188fSccardenas void vioscsi_update_qs(struct vioscsi_dev *); 39195ab188fSccardenas void vioscsi_update_qa(struct vioscsi_dev *); 39295ab188fSccardenas int vioscsi_notifyq(struct vioscsi_dev *); 3936eb4c859Sdv 3946eb4c859Sdv #endif /* _VIRTIO_H_ */ 395