xref: /kvmtool/virtio/blk.c (revision 98790f282f7b7d9d5cbf92af6387c28396be5f89)
1b30d05adSPekka Enberg #include "kvm/blk-virtio.h"
2b30d05adSPekka Enberg 
3c435b91dSPekka Enberg #include "kvm/virtio_blk.h"
4984b7ae0SPekka Enberg #include "kvm/virtio_pci.h"
5b30d05adSPekka Enberg #include "kvm/ioport.h"
68b1ff07eSPekka Enberg #include "kvm/kvm.h"
7b30d05adSPekka Enberg #include "kvm/pci.h"
8b30d05adSPekka Enberg 
98b1ff07eSPekka Enberg #define VIRTIO_BLK_IRQ		14
10984b7ae0SPekka Enberg 
11fbc2fbf9SPekka Enberg struct device {
12c435b91dSPekka Enberg 	uint32_t		host_features;
13fbc2fbf9SPekka Enberg 	uint32_t		guest_features;
14fbc2fbf9SPekka Enberg 	uint8_t			status;
15fbc2fbf9SPekka Enberg };
16fbc2fbf9SPekka Enberg 
17c435b91dSPekka Enberg static struct device device = {
18*98790f28SPekka Enberg 	.host_features		= (1UL << VIRTIO_BLK_F_GEOMETRY)
19c435b91dSPekka Enberg 				| (1UL << VIRTIO_BLK_F_TOPOLOGY)
20c435b91dSPekka Enberg 				| (1UL << VIRTIO_BLK_F_BLK_SIZE),
21c435b91dSPekka Enberg };
22fbc2fbf9SPekka Enberg 
23c435b91dSPekka Enberg #include <stdio.h>
24fbc2fbf9SPekka Enberg static bool blk_virtio_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
25fbc2fbf9SPekka Enberg {
26fbc2fbf9SPekka Enberg 	unsigned long offset;
27fbc2fbf9SPekka Enberg 
28fbc2fbf9SPekka Enberg 	offset		= port - IOPORT_VIRTIO;
29fbc2fbf9SPekka Enberg 
308b1ff07eSPekka Enberg 	/* XXX: Let virtio block device handle this */
318b1ff07eSPekka Enberg 	if (offset >= VIRTIO_PCI_CONFIG_NOMSI)
328b1ff07eSPekka Enberg 		return true;
338b1ff07eSPekka Enberg 
34fbc2fbf9SPekka Enberg 	switch (offset) {
35fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_HOST_FEATURES:
36c435b91dSPekka Enberg 		ioport__write32(data, device.host_features);
37fbc2fbf9SPekka Enberg 		break;
38fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_GUEST_FEATURES:
398b1ff07eSPekka Enberg 		return false;
40fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_QUEUE_PFN:
418b1ff07eSPekka Enberg 		ioport__write32(data, 0x00);
428b1ff07eSPekka Enberg 		break;
43fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_QUEUE_NUM:
448b1ff07eSPekka Enberg 		ioport__write16(data, 0x10);
458b1ff07eSPekka Enberg 		break;
46fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_QUEUE_SEL:
47fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_QUEUE_NOTIFY:
48fbc2fbf9SPekka Enberg 		return false;
49fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_STATUS:
50fbc2fbf9SPekka Enberg 		ioport__write8(data, device.status);
51fbc2fbf9SPekka Enberg 		break;
52fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_ISR:
538b1ff07eSPekka Enberg 		ioport__write8(data, 0x1);
548b1ff07eSPekka Enberg 		kvm__irq_line(self, VIRTIO_BLK_IRQ, 0);
557e61688eSPekka Enberg 		break;
56fbc2fbf9SPekka Enberg 	case VIRTIO_MSI_CONFIG_VECTOR:
57fbc2fbf9SPekka Enberg 	default:
58fbc2fbf9SPekka Enberg 		return false;
59fbc2fbf9SPekka Enberg 	};
60fbc2fbf9SPekka Enberg 
61fbc2fbf9SPekka Enberg 	return true;
62fbc2fbf9SPekka Enberg }
63fbc2fbf9SPekka Enberg 
64fbc2fbf9SPekka Enberg static bool blk_virtio_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
65fbc2fbf9SPekka Enberg {
66fbc2fbf9SPekka Enberg 	unsigned long offset;
67fbc2fbf9SPekka Enberg 
68fbc2fbf9SPekka Enberg 	offset		= port - IOPORT_VIRTIO;
69fbc2fbf9SPekka Enberg 
708b1ff07eSPekka Enberg 	/* XXX: Let virtio block device handle this */
718b1ff07eSPekka Enberg 	if (offset >= VIRTIO_PCI_CONFIG_NOMSI)
728b1ff07eSPekka Enberg 		return true;
738b1ff07eSPekka Enberg 
74fbc2fbf9SPekka Enberg 	switch (offset) {
75fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_GUEST_FEATURES:
76fbc2fbf9SPekka Enberg 		device.guest_features	= ioport__read32(data);
77fbc2fbf9SPekka Enberg 		break;
78fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_QUEUE_PFN:
797e61688eSPekka Enberg 		break;
80fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_QUEUE_SEL:
817e61688eSPekka Enberg 		break;
827e61688eSPekka Enberg 	case VIRTIO_PCI_QUEUE_NOTIFY:
838b1ff07eSPekka Enberg 		kvm__irq_line(self, VIRTIO_BLK_IRQ, 1);
847e61688eSPekka Enberg 		break;
85fbc2fbf9SPekka Enberg 	case VIRTIO_PCI_STATUS:
86fbc2fbf9SPekka Enberg 		device.status		= ioport__read8(data);
87fbc2fbf9SPekka Enberg 		break;
88fbc2fbf9SPekka Enberg 	case VIRTIO_MSI_CONFIG_VECTOR:
89fbc2fbf9SPekka Enberg 	case VIRTIO_MSI_QUEUE_VECTOR:
90fbc2fbf9SPekka Enberg 	default:
91fbc2fbf9SPekka Enberg 		return false;
92fbc2fbf9SPekka Enberg 	};
93fbc2fbf9SPekka Enberg 
94fbc2fbf9SPekka Enberg 	return true;
95fbc2fbf9SPekka Enberg }
96fbc2fbf9SPekka Enberg 
97fbc2fbf9SPekka Enberg static struct ioport_operations blk_virtio_io_ops = {
98fbc2fbf9SPekka Enberg 	.io_in		= blk_virtio_in,
99fbc2fbf9SPekka Enberg 	.io_out		= blk_virtio_out,
100fbc2fbf9SPekka Enberg };
101fbc2fbf9SPekka Enberg 
102b30d05adSPekka Enberg #define PCI_VENDOR_ID_REDHAT_QUMRANET		0x1af4
103b30d05adSPekka Enberg #define PCI_DEVICE_ID_VIRTIO_BLK		0x1001
104b30d05adSPekka Enberg #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET	0x1af4
105b30d05adSPekka Enberg #define PCI_SUBSYSTEM_ID_VIRTIO_BLK		0x0002
106b30d05adSPekka Enberg 
107fbc2fbf9SPekka Enberg static struct pci_device_header blk_virtio_pci_device = {
108b30d05adSPekka Enberg 	.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
109b30d05adSPekka Enberg 	.device_id		= PCI_DEVICE_ID_VIRTIO_BLK,
110b30d05adSPekka Enberg 	.header_type		= PCI_HEADER_TYPE_NORMAL,
111b30d05adSPekka Enberg 	.revision_id		= 0,
112b30d05adSPekka Enberg 	.class			= 0x010000,
113b30d05adSPekka Enberg 	.subsys_vendor_id	= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
114b30d05adSPekka Enberg 	.subsys_id		= PCI_SUBSYSTEM_ID_VIRTIO_BLK,
115b30d05adSPekka Enberg 	.bar[0]			= IOPORT_VIRTIO | PCI_BASE_ADDRESS_SPACE_IO,
116406f1a89SPekka Enberg 	.irq_pin		= 0,
1178b1ff07eSPekka Enberg 	.irq_line		= VIRTIO_BLK_IRQ,
118b30d05adSPekka Enberg };
119b30d05adSPekka Enberg 
120b30d05adSPekka Enberg void blk_virtio__init(void)
121b30d05adSPekka Enberg {
122fbc2fbf9SPekka Enberg 	pci__register(&blk_virtio_pci_device, 1);
123b30d05adSPekka Enberg 
1248b1ff07eSPekka Enberg 	ioport__register(IOPORT_VIRTIO, &blk_virtio_io_ops, 256);
125b30d05adSPekka Enberg }
126