xref: /kvmtool/virtio/blk.c (revision 76b6349f766b6b91e2305c7e1f89d7f80ec8772d)
1b30d05adSPekka Enberg #include "kvm/blk-virtio.h"
2b30d05adSPekka Enberg 
3984b7ae0SPekka Enberg #include "kvm/virtio_pci.h"
4*76b6349fSPekka Enberg 
55a24a9f2SPekka Enberg #include "kvm/disk-image.h"
6*76b6349fSPekka Enberg #include "kvm/virtqueue.h"
7b30d05adSPekka Enberg #include "kvm/ioport.h"
8fe99fd4eSPekka Enberg #include "kvm/util.h"
98b1ff07eSPekka Enberg #include "kvm/kvm.h"
10b30d05adSPekka Enberg #include "kvm/pci.h"
11b30d05adSPekka Enberg 
1220c64ecaSPekka Enberg #include <linux/virtio_ring.h>
1320c64ecaSPekka Enberg #include <linux/virtio_blk.h>
144155ba8cSPekka Enberg #include <inttypes.h>
154155ba8cSPekka Enberg #include <assert.h>
164155ba8cSPekka Enberg 
178b1ff07eSPekka Enberg #define VIRTIO_BLK_IRQ		14
18984b7ae0SPekka Enberg 
1910eca11dSPekka Enberg #define NUM_VIRT_QUEUES		1
2010eca11dSPekka Enberg 
2110eca11dSPekka Enberg #define VIRTIO_BLK_QUEUE_SIZE	16
2210eca11dSPekka Enberg 
23fbc2fbf9SPekka Enberg struct device {
2440ce993fSPekka Enberg 	struct virtio_blk_config	blk_config;
25c435b91dSPekka Enberg 	uint32_t			host_features;
26fbc2fbf9SPekka Enberg 	uint32_t			guest_features;
2740ce993fSPekka Enberg 	uint16_t			config_vector;
28fbc2fbf9SPekka Enberg 	uint8_t				status;
2947bf1d0fSPekka Enberg 
3047bf1d0fSPekka Enberg 	/* virtio queue */
3147bf1d0fSPekka Enberg 	uint16_t			queue_selector;
3210eca11dSPekka Enberg 
3310eca11dSPekka Enberg 	struct virt_queue		virt_queues[NUM_VIRT_QUEUES];
34fbc2fbf9SPekka Enberg };
35fbc2fbf9SPekka Enberg 
3640ce993fSPekka Enberg #define DISK_CYLINDERS	1024
3740ce993fSPekka Enberg #define DISK_HEADS	64
3840ce993fSPekka Enberg #define DISK_SECTORS	32
3940ce993fSPekka Enberg 
40c435b91dSPekka Enberg static struct device device = {
4140ce993fSPekka Enberg 	.blk_config		= (struct virtio_blk_config) {
4240ce993fSPekka Enberg 		.capacity		= DISK_CYLINDERS * DISK_HEADS * DISK_SECTORS,
4340ce993fSPekka Enberg 		/* VIRTIO_BLK_F_GEOMETRY */
4440ce993fSPekka Enberg 		.geometry		= {
4540ce993fSPekka Enberg 			.cylinders		= DISK_CYLINDERS,
4640ce993fSPekka Enberg 			.heads			= DISK_HEADS,
4740ce993fSPekka Enberg 			.sectors		= DISK_SECTORS,
4840ce993fSPekka Enberg 		},
4940ce993fSPekka Enberg 		/* VIRTIO_BLK_SIZE */
5040ce993fSPekka Enberg 		.blk_size		= 4096,
5140ce993fSPekka Enberg 	},
521ef2738dSCyrill Gorcunov 	/*
531ef2738dSCyrill Gorcunov 	 * Note we don't set VIRTIO_BLK_F_GEOMETRY here so the
541ef2738dSCyrill Gorcunov 	 * node kernel will compute disk geometry by own, the
551ef2738dSCyrill Gorcunov 	 * same applies to VIRTIO_BLK_F_BLK_SIZE
561ef2738dSCyrill Gorcunov 	 */
57a267e01bSPekka Enberg 	.host_features		= 0,
58c435b91dSPekka Enberg };
59fbc2fbf9SPekka Enberg 
6040ce993fSPekka Enberg static bool virtio_blk_config_in(void *data, unsigned long offset, int size, uint32_t count)
6140ce993fSPekka Enberg {
6240ce993fSPekka Enberg 	uint8_t *config_space = (uint8_t *) &device.blk_config;
6340ce993fSPekka Enberg 
6440ce993fSPekka Enberg 	if (size != 1 || count != 1)
6540ce993fSPekka Enberg 		return false;
6640ce993fSPekka Enberg 
6740ce993fSPekka Enberg 	ioport__write8(data, config_space[offset - VIRTIO_PCI_CONFIG_NOMSI]);
6840ce993fSPekka Enberg 
6940ce993fSPekka Enberg 	return true;
7040ce993fSPekka Enberg }
7140ce993fSPekka Enberg 
72fbc2fbf9SPekka Enberg static bool blk_virtio_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
73fbc2fbf9SPekka Enberg {
74fbc2fbf9SPekka Enberg 	unsigned long offset;
75fbc2fbf9SPekka Enberg 
76d1888318SCyrill Gorcunov 	offset		= port - IOPORT_VIRTIO_BLK;
77fbc2fbf9SPekka Enberg 
78fbc2fbf9SPekka Enberg 	switch (offset) {
79fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_HOST_FEATURES:
80c435b91dSPekka Enberg 		ioport__write32(data, device.host_features);
81fbc2fbf9SPekka Enberg 		break;
82fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_GUEST_FEATURES:
838b1ff07eSPekka Enberg 		return false;
84fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_QUEUE_PFN:
8510eca11dSPekka Enberg 		ioport__write32(data, device.virt_queues[device.queue_selector].pfn);
868b1ff07eSPekka Enberg 		break;
87fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_QUEUE_NUM:
8810eca11dSPekka Enberg 		ioport__write16(data, VIRTIO_BLK_QUEUE_SIZE);
898b1ff07eSPekka Enberg 		break;
90fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_QUEUE_SEL:
91fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_QUEUE_NOTIFY:
92fbc2fbf9SPekka Enberg 		return false;
93fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_STATUS:
94fbc2fbf9SPekka Enberg 		ioport__write8(data, device.status);
95fbc2fbf9SPekka Enberg 		break;
96fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_ISR:
978b1ff07eSPekka Enberg 		ioport__write8(data, 0x1);
988b1ff07eSPekka Enberg 		kvm__irq_line(self, VIRTIO_BLK_IRQ, 0);
997e61688eSPekka Enberg 		break;
100fbc2fbf9SPekka Enberg 	case VIRTIO_MSI_CONFIG_VECTOR:
10140ce993fSPekka Enberg 		ioport__write16(data, device.config_vector);
10240ce993fSPekka Enberg 		break;
103fbc2fbf9SPekka Enberg 	default:
10440ce993fSPekka Enberg 		return virtio_blk_config_in(data, offset, size, count);
105fbc2fbf9SPekka Enberg 	};
106fbc2fbf9SPekka Enberg 
107fbc2fbf9SPekka Enberg 	return true;
108fbc2fbf9SPekka Enberg }
109fbc2fbf9SPekka Enberg 
110a267e01bSPekka Enberg static bool blk_virtio_read(struct kvm *self, struct virt_queue *queue)
1114155ba8cSPekka Enberg {
1124155ba8cSPekka Enberg 	struct vring_used_elem *used_elem;
1134155ba8cSPekka Enberg 	struct virtio_blk_outhdr *req;
1144155ba8cSPekka Enberg 	struct vring_desc *desc;
115258dd093SPekka Enberg 	uint32_t block_len;
116*76b6349fSPekka Enberg 	uint16_t desc_ndx;
1174155ba8cSPekka Enberg 	uint8_t *status;
118258dd093SPekka Enberg 	void *block;
1194155ba8cSPekka Enberg 
120*76b6349fSPekka Enberg 	desc_ndx		= virt_queue__pop(queue);
1214155ba8cSPekka Enberg 
122a267e01bSPekka Enberg 	if (desc_ndx >= queue->vring.num) {
1234155ba8cSPekka Enberg 		warning("fatal I/O error");
1244155ba8cSPekka Enberg 		return false;
1254155ba8cSPekka Enberg 	}
1264155ba8cSPekka Enberg 
127a267e01bSPekka Enberg 	/* header */
128*76b6349fSPekka Enberg 	desc			= virt_queue__get_desc(queue, desc_ndx);
1294155ba8cSPekka Enberg 	assert(!(desc->flags & VRING_DESC_F_INDIRECT));
1304155ba8cSPekka Enberg 
1314155ba8cSPekka Enberg 	req			= guest_flat_to_host(self, desc->addr);
1324155ba8cSPekka Enberg 
1334155ba8cSPekka Enberg 	/* block */
134*76b6349fSPekka Enberg 	desc			= virt_queue__get_desc(queue, desc->next);
1354155ba8cSPekka Enberg 	assert(!(desc->flags & VRING_DESC_F_INDIRECT));
1364155ba8cSPekka Enberg 
137258dd093SPekka Enberg 	block			= guest_flat_to_host(self, desc->addr);
138258dd093SPekka Enberg 	block_len		= desc->len;
1394155ba8cSPekka Enberg 
140a267e01bSPekka Enberg 	/* status */
141*76b6349fSPekka Enberg 	desc			= virt_queue__get_desc(queue, desc->next);
142a267e01bSPekka Enberg 	assert(!(desc->flags & VRING_DESC_F_INDIRECT));
143a267e01bSPekka Enberg 
144a267e01bSPekka Enberg 	status			= guest_flat_to_host(self, desc->addr);
145a267e01bSPekka Enberg 
146258dd093SPekka Enberg 	switch (req->type) {
147a267e01bSPekka Enberg 	case VIRTIO_BLK_T_IN: {
148a267e01bSPekka Enberg 		int err;
149a267e01bSPekka Enberg 
150258dd093SPekka Enberg 		err		= disk_image__read_sector(self->disk_image, req->sector, block, block_len);
151a267e01bSPekka Enberg 		if (err)
152a267e01bSPekka Enberg 			*status			= VIRTIO_BLK_S_IOERR;
153a267e01bSPekka Enberg 		else
154a267e01bSPekka Enberg 			*status			= VIRTIO_BLK_S_OK;
155258dd093SPekka Enberg 		break;
156a267e01bSPekka Enberg 	}
157a267e01bSPekka Enberg 	case VIRTIO_BLK_T_OUT: {
158a267e01bSPekka Enberg 		int err;
159a267e01bSPekka Enberg 
160258dd093SPekka Enberg 		err		= disk_image__write_sector(self->disk_image, req->sector, block, block_len);
161a267e01bSPekka Enberg 		if (err)
162a267e01bSPekka Enberg 			*status			= VIRTIO_BLK_S_IOERR;
163a267e01bSPekka Enberg 		else
164a267e01bSPekka Enberg 			*status			= VIRTIO_BLK_S_OK;
165258dd093SPekka Enberg 		break;
166a267e01bSPekka Enberg 	}
167258dd093SPekka Enberg 	default:
1684155ba8cSPekka Enberg 		warning("request type %d", req->type);
169a267e01bSPekka Enberg 		*status			= VIRTIO_BLK_S_IOERR;
170a2c8c696SAsias He 		break;
171a2c8c696SAsias He 	}
172a2c8c696SAsias He 
173*76b6349fSPekka Enberg 	used_elem		= virt_queue__get_used_elem(queue);
174a267e01bSPekka Enberg 
175a267e01bSPekka Enberg 	used_elem->id		= desc_ndx;
176a267e01bSPekka Enberg 	used_elem->len		= 3;
1774155ba8cSPekka Enberg 
1784155ba8cSPekka Enberg 	return true;
1794155ba8cSPekka Enberg }
1804155ba8cSPekka Enberg 
181fbc2fbf9SPekka Enberg static bool blk_virtio_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
182fbc2fbf9SPekka Enberg {
183fbc2fbf9SPekka Enberg 	unsigned long offset;
184fbc2fbf9SPekka Enberg 
185d1888318SCyrill Gorcunov 	offset		= port - IOPORT_VIRTIO_BLK;
186fbc2fbf9SPekka Enberg 
187fbc2fbf9SPekka Enberg 	switch (offset) {
188fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_GUEST_FEATURES:
189fbc2fbf9SPekka Enberg 		device.guest_features	= ioport__read32(data);
190fbc2fbf9SPekka Enberg 		break;
19110eca11dSPekka Enberg 	case VIRTIO_PCI_QUEUE_PFN: {
19210eca11dSPekka Enberg 		struct virt_queue *queue;
19310eca11dSPekka Enberg 		void *p;
19410eca11dSPekka Enberg 
19510eca11dSPekka Enberg 		queue			= &device.virt_queues[device.queue_selector];
19610eca11dSPekka Enberg 
19710eca11dSPekka Enberg 		queue->pfn		= ioport__read32(data);
19810eca11dSPekka Enberg 
19910eca11dSPekka Enberg 		p			= guest_flat_to_host(self, queue->pfn << 12);
20010eca11dSPekka Enberg 
20110eca11dSPekka Enberg 		vring_init(&queue->vring, VIRTIO_BLK_QUEUE_SIZE, p, 4096);
20210eca11dSPekka Enberg 
2037e61688eSPekka Enberg 		break;
20410eca11dSPekka Enberg 	}
205fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_QUEUE_SEL:
20647bf1d0fSPekka Enberg 		device.queue_selector	= ioport__read16(data);
2077e61688eSPekka Enberg 		break;
20810eca11dSPekka Enberg 	case VIRTIO_PCI_QUEUE_NOTIFY: {
20910eca11dSPekka Enberg 		struct virt_queue *queue;
21010eca11dSPekka Enberg 		uint16_t queue_index;
21110eca11dSPekka Enberg 
21210eca11dSPekka Enberg 		queue_index		= ioport__read16(data);
21310eca11dSPekka Enberg 
21410eca11dSPekka Enberg 		queue			= &device.virt_queues[queue_index];
21510eca11dSPekka Enberg 
2164155ba8cSPekka Enberg 		while (queue->vring.avail->idx != queue->last_avail_idx) {
217a267e01bSPekka Enberg 			if (!blk_virtio_read(self, queue))
2184155ba8cSPekka Enberg 				return false;
21993d18b72SPekka Enberg 		}
2208b1ff07eSPekka Enberg 		kvm__irq_line(self, VIRTIO_BLK_IRQ, 1);
2215a24a9f2SPekka Enberg 
2227e61688eSPekka Enberg 		break;
22310eca11dSPekka Enberg 	}
224fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_STATUS:
225fbc2fbf9SPekka Enberg 		device.status		= ioport__read8(data);
226fbc2fbf9SPekka Enberg 		break;
227fbc2fbf9SPekka Enberg 	case VIRTIO_MSI_CONFIG_VECTOR:
22840ce993fSPekka Enberg 		device.config_vector	= VIRTIO_MSI_NO_VECTOR;
22940ce993fSPekka Enberg 		break;
230fbc2fbf9SPekka Enberg 	case VIRTIO_MSI_QUEUE_VECTOR:
23140ce993fSPekka Enberg 		break;
232fbc2fbf9SPekka Enberg 	default:
233fbc2fbf9SPekka Enberg 		return false;
234fbc2fbf9SPekka Enberg 	};
235fbc2fbf9SPekka Enberg 
236fbc2fbf9SPekka Enberg 	return true;
237fbc2fbf9SPekka Enberg }
238fbc2fbf9SPekka Enberg 
239fbc2fbf9SPekka Enberg static struct ioport_operations blk_virtio_io_ops = {
240fbc2fbf9SPekka Enberg 	.io_in		= blk_virtio_in,
241fbc2fbf9SPekka Enberg 	.io_out		= blk_virtio_out,
242fbc2fbf9SPekka Enberg };
243fbc2fbf9SPekka Enberg 
244b30d05adSPekka Enberg #define PCI_VENDOR_ID_REDHAT_QUMRANET		0x1af4
245b30d05adSPekka Enberg #define PCI_DEVICE_ID_VIRTIO_BLK		0x1001
246b30d05adSPekka Enberg #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET	0x1af4
247b30d05adSPekka Enberg #define PCI_SUBSYSTEM_ID_VIRTIO_BLK		0x0002
248b30d05adSPekka Enberg 
249fbc2fbf9SPekka Enberg static struct pci_device_header blk_virtio_pci_device = {
250b30d05adSPekka Enberg 	.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
251b30d05adSPekka Enberg 	.device_id		= PCI_DEVICE_ID_VIRTIO_BLK,
252b30d05adSPekka Enberg 	.header_type		= PCI_HEADER_TYPE_NORMAL,
253b30d05adSPekka Enberg 	.revision_id		= 0,
254b30d05adSPekka Enberg 	.class			= 0x010000,
255b30d05adSPekka Enberg 	.subsys_vendor_id	= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
256b30d05adSPekka Enberg 	.subsys_id		= PCI_SUBSYSTEM_ID_VIRTIO_BLK,
257d1888318SCyrill Gorcunov 	.bar[0]			= IOPORT_VIRTIO_BLK | PCI_BASE_ADDRESS_SPACE_IO,
258dc53a427SPekka Enberg 	.irq_pin		= 1,
2598b1ff07eSPekka Enberg 	.irq_line		= VIRTIO_BLK_IRQ,
260b30d05adSPekka Enberg };
261b30d05adSPekka Enberg 
262ca7c891bSCyrill Gorcunov void blk_virtio__init(struct kvm *self)
263b30d05adSPekka Enberg {
2641f848897SPekka Enberg 	if (!self->disk_image)
2651f848897SPekka Enberg 		return;
2661f848897SPekka Enberg 
267a267e01bSPekka Enberg 	device.blk_config.capacity = self->disk_image->size / SECTOR_SIZE;
268ca7c891bSCyrill Gorcunov 
269fbc2fbf9SPekka Enberg 	pci__register(&blk_virtio_pci_device, 1);
270b30d05adSPekka Enberg 
271d1888318SCyrill Gorcunov 	ioport__register(IOPORT_VIRTIO_BLK, &blk_virtio_io_ops, 256);
272b30d05adSPekka Enberg }
273