xref: /kvmtool/virtio/blk.c (revision 0528c2a76d75df8c46de799bb61500132fa5319f)
1416b2c2dSAsias He #include "kvm/virtio-blk.h"
2b30d05adSPekka Enberg 
3416b2c2dSAsias He #include "kvm/virtio-pci.h"
476b6349fSPekka Enberg 
55a24a9f2SPekka Enberg #include "kvm/disk-image.h"
639d6af07SAsias He #include "kvm/virtio.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>
14*0528c2a7SPekka Enberg 
154155ba8cSPekka Enberg #include <inttypes.h>
16*0528c2a7SPekka Enberg #include <pthread.h>
174155ba8cSPekka Enberg 
188b1ff07eSPekka Enberg #define VIRTIO_BLK_IRQ		14
19984b7ae0SPekka Enberg 
2010eca11dSPekka Enberg #define NUM_VIRT_QUEUES		1
2110eca11dSPekka Enberg 
2203110ff3SAsias He #define VIRTIO_BLK_QUEUE_SIZE	128
2310eca11dSPekka Enberg 
24802e07a0SAsias He struct blk_device {
25*0528c2a7SPekka Enberg 	pthread_mutex_t			mutex;
26*0528c2a7SPekka Enberg 
2740ce993fSPekka Enberg 	struct virtio_blk_config	blk_config;
28c435b91dSPekka Enberg 	uint32_t			host_features;
29fbc2fbf9SPekka Enberg 	uint32_t			guest_features;
3040ce993fSPekka Enberg 	uint16_t			config_vector;
31fbc2fbf9SPekka Enberg 	uint8_t				status;
3247bf1d0fSPekka Enberg 
3347bf1d0fSPekka Enberg 	/* virtio queue */
3447bf1d0fSPekka Enberg 	uint16_t			queue_selector;
3510eca11dSPekka Enberg 
3645e47970SAsias He 	struct virt_queue		vqs[NUM_VIRT_QUEUES];
37fbc2fbf9SPekka Enberg };
38fbc2fbf9SPekka Enberg 
3903110ff3SAsias He #define DISK_SEG_MAX	126
4040ce993fSPekka Enberg 
41802e07a0SAsias He static struct blk_device blk_device = {
42*0528c2a7SPekka Enberg 	.mutex			= PTHREAD_MUTEX_INITIALIZER,
43*0528c2a7SPekka Enberg 
4440ce993fSPekka Enberg 	.blk_config		= (struct virtio_blk_config) {
45e199f440SPekka Enberg 		/* VIRTIO_BLK_F_SEG_MAX */
4603110ff3SAsias He 		.seg_max		= DISK_SEG_MAX,
4740ce993fSPekka Enberg 	},
481ef2738dSCyrill Gorcunov 	/*
491ef2738dSCyrill Gorcunov 	 * Note we don't set VIRTIO_BLK_F_GEOMETRY here so the
501ef2738dSCyrill Gorcunov 	 * node kernel will compute disk geometry by own, the
511ef2738dSCyrill Gorcunov 	 * same applies to VIRTIO_BLK_F_BLK_SIZE
521ef2738dSCyrill Gorcunov 	 */
5303110ff3SAsias He 	.host_features		= (1UL << VIRTIO_BLK_F_SEG_MAX),
54c435b91dSPekka Enberg };
55fbc2fbf9SPekka Enberg 
56416b2c2dSAsias He static bool virtio_blk_pci_io_device_specific_in(void *data, unsigned long offset, int size, uint32_t count)
5740ce993fSPekka Enberg {
58802e07a0SAsias He 	uint8_t *config_space = (uint8_t *) &blk_device.blk_config;
5940ce993fSPekka Enberg 
6040ce993fSPekka Enberg 	if (size != 1 || count != 1)
6140ce993fSPekka Enberg 		return false;
6240ce993fSPekka Enberg 
6340ce993fSPekka Enberg 	ioport__write8(data, config_space[offset - VIRTIO_PCI_CONFIG_NOMSI]);
6440ce993fSPekka Enberg 
6540ce993fSPekka Enberg 	return true;
6640ce993fSPekka Enberg }
6740ce993fSPekka Enberg 
68416b2c2dSAsias He static bool virtio_blk_pci_io_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
69fbc2fbf9SPekka Enberg {
70fbc2fbf9SPekka Enberg 	unsigned long offset;
71*0528c2a7SPekka Enberg 	bool ret = true;
72*0528c2a7SPekka Enberg 
73*0528c2a7SPekka Enberg 	if (pthread_mutex_lock(&blk_device.mutex) < 0)
74*0528c2a7SPekka Enberg 		die("pthread_mutex_lock");
75fbc2fbf9SPekka Enberg 
76d1888318SCyrill Gorcunov 	offset		= port - IOPORT_VIRTIO_BLK;
77fbc2fbf9SPekka Enberg 
78fbc2fbf9SPekka Enberg 	switch (offset) {
79fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_HOST_FEATURES:
80802e07a0SAsias He 		ioport__write32(data, blk_device.host_features);
81fbc2fbf9SPekka Enberg 		break;
82fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_GUEST_FEATURES:
83*0528c2a7SPekka Enberg 		ret		= false;
84*0528c2a7SPekka Enberg 		goto out_unlock;
85fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_QUEUE_PFN:
8645e47970SAsias He 		ioport__write32(data, blk_device.vqs[blk_device.queue_selector].pfn);
878b1ff07eSPekka Enberg 		break;
88fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_QUEUE_NUM:
8910eca11dSPekka Enberg 		ioport__write16(data, VIRTIO_BLK_QUEUE_SIZE);
908b1ff07eSPekka Enberg 		break;
91fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_QUEUE_SEL:
92fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_QUEUE_NOTIFY:
93*0528c2a7SPekka Enberg 		ret		= false;
94*0528c2a7SPekka Enberg 		goto out_unlock;
95fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_STATUS:
96802e07a0SAsias He 		ioport__write8(data, blk_device.status);
97fbc2fbf9SPekka Enberg 		break;
98fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_ISR:
998b1ff07eSPekka Enberg 		ioport__write8(data, 0x1);
1008b1ff07eSPekka Enberg 		kvm__irq_line(self, VIRTIO_BLK_IRQ, 0);
1017e61688eSPekka Enberg 		break;
102fbc2fbf9SPekka Enberg 	case VIRTIO_MSI_CONFIG_VECTOR:
103802e07a0SAsias He 		ioport__write16(data, blk_device.config_vector);
10440ce993fSPekka Enberg 		break;
105fbc2fbf9SPekka Enberg 	default:
106*0528c2a7SPekka Enberg 		ret		= virtio_blk_pci_io_device_specific_in(data, offset, size, count);
107*0528c2a7SPekka Enberg 		goto out_unlock;
108fbc2fbf9SPekka Enberg 	};
109fbc2fbf9SPekka Enberg 
110*0528c2a7SPekka Enberg out_unlock:
111*0528c2a7SPekka Enberg 	if (pthread_mutex_unlock(&blk_device.mutex) < 0)
112*0528c2a7SPekka Enberg 		die("pthread_mutex_unlock");
113*0528c2a7SPekka Enberg 
114*0528c2a7SPekka Enberg 	return ret;
115fbc2fbf9SPekka Enberg }
116fbc2fbf9SPekka Enberg 
11745e47970SAsias He static bool virtio_blk_do_io_request(struct kvm *self, struct virt_queue *queue)
1184155ba8cSPekka Enberg {
11945e47970SAsias He 	struct iovec iov[VIRTIO_BLK_QUEUE_SIZE];
1204155ba8cSPekka Enberg 	struct virtio_blk_outhdr *req;
12145e47970SAsias He 	uint32_t block_len, block_cnt;
12245e47970SAsias He 	uint16_t out, in, head;
1234155ba8cSPekka Enberg 	uint8_t *status;
124f0952e64SPekka Enberg 	bool io_error;
125258dd093SPekka Enberg 	void *block;
126f0952e64SPekka Enberg 	int err, i;
127f0952e64SPekka Enberg 
128f0952e64SPekka Enberg 	io_error	= false;
1294155ba8cSPekka Enberg 
13045e47970SAsias He 	head		= virt_queue__get_iov(queue, iov, &out, &in, self);
1314155ba8cSPekka Enberg 
13245e47970SAsias He 	/* head */
13345e47970SAsias He 	req		= iov[0].iov_base;
13403110ff3SAsias He 
1354155ba8cSPekka Enberg 	/* block */
13603110ff3SAsias He 	block_cnt	= 0;
13703110ff3SAsias He 
13845e47970SAsias He 	for (i = 1; i < out + in - 1; i++) {
13945e47970SAsias He 		block		= iov[i].iov_base;
14045e47970SAsias He 		block_len	= iov[i].iov_len;
1414155ba8cSPekka Enberg 
142258dd093SPekka Enberg 		switch (req->type) {
14303110ff3SAsias He 		case VIRTIO_BLK_T_IN:
144258dd093SPekka Enberg 			err	= disk_image__read_sector(self->disk_image, req->sector, block, block_len);
145258dd093SPekka Enberg 			break;
14603110ff3SAsias He 		case VIRTIO_BLK_T_OUT:
147258dd093SPekka Enberg 			err	= disk_image__write_sector(self->disk_image, req->sector, block, block_len);
148258dd093SPekka Enberg 			break;
149258dd093SPekka Enberg 		default:
1504155ba8cSPekka Enberg 			warning("request type %d", req->type);
151f0952e64SPekka Enberg 			io_error	= true;
152a2c8c696SAsias He 		}
153a2c8c696SAsias He 
15403110ff3SAsias He 		req->sector	+= block_len >> SECTOR_SHIFT;
15503110ff3SAsias He 		block_cnt	+= block_len;
15603110ff3SAsias He 	}
15703110ff3SAsias He 
15845e47970SAsias He 	/* status */
15945e47970SAsias He 	status			= iov[out + in - 1].iov_base;
160f0952e64SPekka Enberg 	*status			= io_error ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK;
16103110ff3SAsias He 
16245e47970SAsias He 	virt_queue__set_used_elem(queue, head, block_cnt);
1634155ba8cSPekka Enberg 
1644155ba8cSPekka Enberg 	return true;
1654155ba8cSPekka Enberg }
1664155ba8cSPekka Enberg 
16745e47970SAsias He static void virtio_blk_handle_callback(struct kvm *self, uint16_t queue_index)
16845e47970SAsias He {
1690ea58e5bSPekka Enberg 	struct virt_queue *vq = &blk_device.vqs[queue_index];
17045e47970SAsias He 
1710ea58e5bSPekka Enberg 	while (virt_queue__available(vq))
17245e47970SAsias He 		virtio_blk_do_io_request(self, vq);
1730ea58e5bSPekka Enberg 
17445e47970SAsias He 	kvm__irq_line(self, VIRTIO_BLK_IRQ, 1);
17545e47970SAsias He 
17645e47970SAsias He }
177*0528c2a7SPekka Enberg 
178416b2c2dSAsias He static bool virtio_blk_pci_io_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
179fbc2fbf9SPekka Enberg {
180fbc2fbf9SPekka Enberg 	unsigned long offset;
181*0528c2a7SPekka Enberg 	bool ret = true;
182*0528c2a7SPekka Enberg 
183*0528c2a7SPekka Enberg 	if (pthread_mutex_lock(&blk_device.mutex) < 0)
184*0528c2a7SPekka Enberg 		die("pthread_mutex_lock");
185fbc2fbf9SPekka Enberg 
186d1888318SCyrill Gorcunov 	offset		= port - IOPORT_VIRTIO_BLK;
187fbc2fbf9SPekka Enberg 
188fbc2fbf9SPekka Enberg 	switch (offset) {
189fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_GUEST_FEATURES:
190802e07a0SAsias He 		blk_device.guest_features	= ioport__read32(data);
191fbc2fbf9SPekka Enberg 		break;
19210eca11dSPekka Enberg 	case VIRTIO_PCI_QUEUE_PFN: {
19310eca11dSPekka Enberg 		struct virt_queue *queue;
19410eca11dSPekka Enberg 		void *p;
19510eca11dSPekka Enberg 
19645e47970SAsias He 		queue			= &blk_device.vqs[blk_device.queue_selector];
19710eca11dSPekka Enberg 
19810eca11dSPekka Enberg 		queue->pfn		= ioport__read32(data);
19910eca11dSPekka Enberg 
20010eca11dSPekka Enberg 		p			= guest_flat_to_host(self, queue->pfn << 12);
20110eca11dSPekka Enberg 
20210eca11dSPekka Enberg 		vring_init(&queue->vring, VIRTIO_BLK_QUEUE_SIZE, p, 4096);
20310eca11dSPekka Enberg 
2047e61688eSPekka Enberg 		break;
20510eca11dSPekka Enberg 	}
206fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_QUEUE_SEL:
207802e07a0SAsias He 		blk_device.queue_selector	= ioport__read16(data);
2087e61688eSPekka Enberg 		break;
20910eca11dSPekka Enberg 	case VIRTIO_PCI_QUEUE_NOTIFY: {
21010eca11dSPekka Enberg 		uint16_t queue_index;
21110eca11dSPekka Enberg 		queue_index		= ioport__read16(data);
21245e47970SAsias He 		virtio_blk_handle_callback(self, queue_index);
2137e61688eSPekka Enberg 		break;
21410eca11dSPekka Enberg 	}
215fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_STATUS:
216802e07a0SAsias He 		blk_device.status		= ioport__read8(data);
217fbc2fbf9SPekka Enberg 		break;
218fbc2fbf9SPekka Enberg 	case VIRTIO_MSI_CONFIG_VECTOR:
219802e07a0SAsias He 		blk_device.config_vector	= VIRTIO_MSI_NO_VECTOR;
22040ce993fSPekka Enberg 		break;
221fbc2fbf9SPekka Enberg 	case VIRTIO_MSI_QUEUE_VECTOR:
22240ce993fSPekka Enberg 		break;
223fbc2fbf9SPekka Enberg 	default:
224*0528c2a7SPekka Enberg 		ret		= false;
225*0528c2a7SPekka Enberg 		goto out_unlock;
226fbc2fbf9SPekka Enberg 	};
227fbc2fbf9SPekka Enberg 
228*0528c2a7SPekka Enberg out_unlock:
229*0528c2a7SPekka Enberg 	if (pthread_mutex_unlock(&blk_device.mutex) < 0)
230*0528c2a7SPekka Enberg 		die("pthread_mutex_unlock");
231*0528c2a7SPekka Enberg 
232*0528c2a7SPekka Enberg 	return ret;
233fbc2fbf9SPekka Enberg }
234fbc2fbf9SPekka Enberg 
235416b2c2dSAsias He static struct ioport_operations virtio_blk_io_ops = {
236416b2c2dSAsias He 	.io_in		= virtio_blk_pci_io_in,
237416b2c2dSAsias He 	.io_out		= virtio_blk_pci_io_out,
238fbc2fbf9SPekka Enberg };
239fbc2fbf9SPekka Enberg 
240b30d05adSPekka Enberg #define PCI_VENDOR_ID_REDHAT_QUMRANET		0x1af4
241b30d05adSPekka Enberg #define PCI_DEVICE_ID_VIRTIO_BLK		0x1001
242b30d05adSPekka Enberg #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET	0x1af4
243b30d05adSPekka Enberg #define PCI_SUBSYSTEM_ID_VIRTIO_BLK		0x0002
244b30d05adSPekka Enberg 
245416b2c2dSAsias He static struct pci_device_header virtio_blk_pci_device = {
246b30d05adSPekka Enberg 	.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
247b30d05adSPekka Enberg 	.device_id		= PCI_DEVICE_ID_VIRTIO_BLK,
248b30d05adSPekka Enberg 	.header_type		= PCI_HEADER_TYPE_NORMAL,
249b30d05adSPekka Enberg 	.revision_id		= 0,
250b30d05adSPekka Enberg 	.class			= 0x010000,
251b30d05adSPekka Enberg 	.subsys_vendor_id	= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
252b30d05adSPekka Enberg 	.subsys_id		= PCI_SUBSYSTEM_ID_VIRTIO_BLK,
253d1888318SCyrill Gorcunov 	.bar[0]			= IOPORT_VIRTIO_BLK | PCI_BASE_ADDRESS_SPACE_IO,
254dc53a427SPekka Enberg 	.irq_pin		= 1,
2558b1ff07eSPekka Enberg 	.irq_line		= VIRTIO_BLK_IRQ,
256b30d05adSPekka Enberg };
257b30d05adSPekka Enberg 
258f05bbe8dSAsias He #define PCI_VIRTIO_BLK_DEVNUM 1
259f05bbe8dSAsias He 
260416b2c2dSAsias He void virtio_blk__init(struct kvm *self)
261b30d05adSPekka Enberg {
2621f848897SPekka Enberg 	if (!self->disk_image)
2631f848897SPekka Enberg 		return;
2641f848897SPekka Enberg 
265802e07a0SAsias He 	blk_device.blk_config.capacity = self->disk_image->size / SECTOR_SIZE;
266ca7c891bSCyrill Gorcunov 
267416b2c2dSAsias He 	pci__register(&virtio_blk_pci_device, PCI_VIRTIO_BLK_DEVNUM);
268b30d05adSPekka Enberg 
269416b2c2dSAsias He 	ioport__register(IOPORT_VIRTIO_BLK, &virtio_blk_io_ops, IOPORT_VIRTIO_BLK_SIZE);
270b30d05adSPekka Enberg }
271