xref: /kvmtool/virtio/console.c (revision 9bd8ac5c92de4327829af2d67db38b4f4f6b9010)
1*9bd8ac5cSAsias He #include "kvm/console-virtio.h"
2*9bd8ac5cSAsias He #include "kvm/virtio_pci.h"
3*9bd8ac5cSAsias He #include "kvm/disk-image.h"
4*9bd8ac5cSAsias He #include "kvm/virtqueue.h"
5*9bd8ac5cSAsias He #include "kvm/ioport.h"
6*9bd8ac5cSAsias He #include "kvm/util.h"
7*9bd8ac5cSAsias He #include "kvm/term.h"
8*9bd8ac5cSAsias He #include "kvm/kvm.h"
9*9bd8ac5cSAsias He #include "kvm/pci.h"
10*9bd8ac5cSAsias He 
11*9bd8ac5cSAsias He #include <linux/virtio_console.h>
12*9bd8ac5cSAsias He #include <linux/virtio_ring.h>
13*9bd8ac5cSAsias He #include <linux/virtio_blk.h>
14*9bd8ac5cSAsias He 
15*9bd8ac5cSAsias He #include <sys/uio.h>
16*9bd8ac5cSAsias He #include <sys/types.h>
17*9bd8ac5cSAsias He #include <sys/stat.h>
18*9bd8ac5cSAsias He #include <inttypes.h>
19*9bd8ac5cSAsias He #include <termios.h>
20*9bd8ac5cSAsias He #include <assert.h>
21*9bd8ac5cSAsias He #include <unistd.h>
22*9bd8ac5cSAsias He #include <fcntl.h>
23*9bd8ac5cSAsias He 
24*9bd8ac5cSAsias He #define VIRTIO_CONSOLE_IRQ		14
25*9bd8ac5cSAsias He #define VIRTIO_CONSOLE_QUEUE_SIZE	128
26*9bd8ac5cSAsias He #define VIRTIO_CONSOLE_NUM_QUEUES	2
27*9bd8ac5cSAsias He #define VIRTIO_CONSOLE_RX_QUEUE		0
28*9bd8ac5cSAsias He #define VIRTIO_CONSOLE_TX_QUEUE		1
29*9bd8ac5cSAsias He #define PCI_VIRTIO_CONSOLE_DEVNUM	2
30*9bd8ac5cSAsias He 
31*9bd8ac5cSAsias He struct console_device {
32*9bd8ac5cSAsias He 	struct virt_queue		vqs[VIRTIO_CONSOLE_NUM_QUEUES];
33*9bd8ac5cSAsias He 	struct virtio_console_config	console_config;
34*9bd8ac5cSAsias He 	uint32_t			host_features;
35*9bd8ac5cSAsias He 	uint32_t			guest_features;
36*9bd8ac5cSAsias He 	uint16_t			config_vector;
37*9bd8ac5cSAsias He 	uint8_t				status;
38*9bd8ac5cSAsias He 	uint16_t			queue_selector;
39*9bd8ac5cSAsias He };
40*9bd8ac5cSAsias He 
41*9bd8ac5cSAsias He static struct console_device console_device = {
42*9bd8ac5cSAsias He 	.console_config = {
43*9bd8ac5cSAsias He 		.cols		= 80,
44*9bd8ac5cSAsias He 		.rows		= 24,
45*9bd8ac5cSAsias He 		.max_nr_ports	= 1,
46*9bd8ac5cSAsias He 	},
47*9bd8ac5cSAsias He 
48*9bd8ac5cSAsias He 	.host_features		= 0,
49*9bd8ac5cSAsias He };
50*9bd8ac5cSAsias He 
51*9bd8ac5cSAsias He /*
52*9bd8ac5cSAsias He  * Interrupts are injected for hvc0 only.
53*9bd8ac5cSAsias He  */
54*9bd8ac5cSAsias He void virtio_console__inject_interrupt(struct kvm *self)
55*9bd8ac5cSAsias He {
56*9bd8ac5cSAsias He 	struct iovec iov[VIRTIO_CONSOLE_QUEUE_SIZE];
57*9bd8ac5cSAsias He 	struct virt_queue *vq;
58*9bd8ac5cSAsias He 	uint16_t out, in;
59*9bd8ac5cSAsias He 	uint16_t head;
60*9bd8ac5cSAsias He 	int len;
61*9bd8ac5cSAsias He 
62*9bd8ac5cSAsias He 	vq = &console_device.vqs[VIRTIO_CONSOLE_RX_QUEUE];
63*9bd8ac5cSAsias He 
64*9bd8ac5cSAsias He 	if (term_readable(CONSOLE_VIRTIO) && virt_queue__available(vq)) {
65*9bd8ac5cSAsias He 		head = virt_queue__get_iov(vq, iov, &out, &in, self);
66*9bd8ac5cSAsias He 		len = term_getc_iov(CONSOLE_VIRTIO, iov, in);
67*9bd8ac5cSAsias He 		virt_queue__set_used_elem(vq, head, len);
68*9bd8ac5cSAsias He 		kvm__irq_line(self, VIRTIO_CONSOLE_IRQ, 1);
69*9bd8ac5cSAsias He 	}
70*9bd8ac5cSAsias He }
71*9bd8ac5cSAsias He 
72*9bd8ac5cSAsias He static bool virtio_console_pci_io_device_specific_in(void *data, unsigned long offset, int size, uint32_t count)
73*9bd8ac5cSAsias He {
74*9bd8ac5cSAsias He 	uint8_t *config_space = (uint8_t *) &console_device.console_config;
75*9bd8ac5cSAsias He 
76*9bd8ac5cSAsias He 	if (size != 1 || count != 1)
77*9bd8ac5cSAsias He 		return false;
78*9bd8ac5cSAsias He 
79*9bd8ac5cSAsias He 	if ((offset - VIRTIO_PCI_CONFIG_NOMSI) > sizeof(struct virtio_console_config))
80*9bd8ac5cSAsias He 		error("config offset is too big: %li", offset - VIRTIO_PCI_CONFIG_NOMSI);
81*9bd8ac5cSAsias He 
82*9bd8ac5cSAsias He 	ioport__write8(data, config_space[offset - VIRTIO_PCI_CONFIG_NOMSI]);
83*9bd8ac5cSAsias He 
84*9bd8ac5cSAsias He 	return true;
85*9bd8ac5cSAsias He }
86*9bd8ac5cSAsias He 
87*9bd8ac5cSAsias He static bool virtio_console_pci_io_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
88*9bd8ac5cSAsias He {
89*9bd8ac5cSAsias He 	unsigned long offset = port - IOPORT_VIRTIO_CONSOLE;
90*9bd8ac5cSAsias He 
91*9bd8ac5cSAsias He 	switch (offset) {
92*9bd8ac5cSAsias He 	case VIRTIO_PCI_HOST_FEATURES:
93*9bd8ac5cSAsias He 		ioport__write32(data, console_device.host_features);
94*9bd8ac5cSAsias He 		break;
95*9bd8ac5cSAsias He 	case VIRTIO_PCI_GUEST_FEATURES:
96*9bd8ac5cSAsias He 		return false;
97*9bd8ac5cSAsias He 	case VIRTIO_PCI_QUEUE_PFN:
98*9bd8ac5cSAsias He 		ioport__write32(data, console_device.vqs[console_device.queue_selector].pfn);
99*9bd8ac5cSAsias He 		break;
100*9bd8ac5cSAsias He 	case VIRTIO_PCI_QUEUE_NUM:
101*9bd8ac5cSAsias He 		ioport__write16(data, VIRTIO_CONSOLE_QUEUE_SIZE);
102*9bd8ac5cSAsias He 		break;
103*9bd8ac5cSAsias He 	case VIRTIO_PCI_QUEUE_SEL:
104*9bd8ac5cSAsias He 	case VIRTIO_PCI_QUEUE_NOTIFY:
105*9bd8ac5cSAsias He 		return false;
106*9bd8ac5cSAsias He 	case VIRTIO_PCI_STATUS:
107*9bd8ac5cSAsias He 		ioport__write8(data, console_device.status);
108*9bd8ac5cSAsias He 		break;
109*9bd8ac5cSAsias He 	case VIRTIO_PCI_ISR:
110*9bd8ac5cSAsias He 		ioport__write8(data, 0x1);
111*9bd8ac5cSAsias He 		kvm__irq_line(self, VIRTIO_CONSOLE_IRQ, 0);
112*9bd8ac5cSAsias He 		break;
113*9bd8ac5cSAsias He 	case VIRTIO_MSI_CONFIG_VECTOR:
114*9bd8ac5cSAsias He 		ioport__write16(data, console_device.config_vector);
115*9bd8ac5cSAsias He 		break;
116*9bd8ac5cSAsias He 	default:
117*9bd8ac5cSAsias He 		return virtio_console_pci_io_device_specific_in(data, offset, size, count);
118*9bd8ac5cSAsias He 	};
119*9bd8ac5cSAsias He 
120*9bd8ac5cSAsias He 	return true;
121*9bd8ac5cSAsias He }
122*9bd8ac5cSAsias He 
123*9bd8ac5cSAsias He static void virtio_console_handle_callback(struct kvm *self, uint16_t queue_index)
124*9bd8ac5cSAsias He {
125*9bd8ac5cSAsias He 	struct iovec iov[VIRTIO_CONSOLE_QUEUE_SIZE];
126*9bd8ac5cSAsias He 	struct virt_queue *vq;
127*9bd8ac5cSAsias He 	uint16_t out, in;
128*9bd8ac5cSAsias He 	uint16_t head;
129*9bd8ac5cSAsias He 	uint32_t len;
130*9bd8ac5cSAsias He 
131*9bd8ac5cSAsias He 	vq = &console_device.vqs[queue_index];
132*9bd8ac5cSAsias He 
133*9bd8ac5cSAsias He 	if (queue_index == VIRTIO_CONSOLE_TX_QUEUE) {
134*9bd8ac5cSAsias He 
135*9bd8ac5cSAsias He 		while (virt_queue__available(vq)) {
136*9bd8ac5cSAsias He 			head = virt_queue__get_iov(vq, iov, &out, &in, self);
137*9bd8ac5cSAsias He 			len = term_putc_iov(CONSOLE_VIRTIO, iov, out);
138*9bd8ac5cSAsias He 			virt_queue__set_used_elem(vq, head, len);
139*9bd8ac5cSAsias He 		}
140*9bd8ac5cSAsias He 
141*9bd8ac5cSAsias He 		kvm__irq_line(self, VIRTIO_CONSOLE_IRQ, 1);
142*9bd8ac5cSAsias He 	}
143*9bd8ac5cSAsias He }
144*9bd8ac5cSAsias He 
145*9bd8ac5cSAsias He static bool virtio_console_pci_io_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
146*9bd8ac5cSAsias He {
147*9bd8ac5cSAsias He 	unsigned long offset = port - IOPORT_VIRTIO_CONSOLE;
148*9bd8ac5cSAsias He 
149*9bd8ac5cSAsias He 	switch (offset) {
150*9bd8ac5cSAsias He 	case VIRTIO_PCI_GUEST_FEATURES:
151*9bd8ac5cSAsias He 		console_device.guest_features	= ioport__read32(data);
152*9bd8ac5cSAsias He 		break;
153*9bd8ac5cSAsias He 	case VIRTIO_PCI_QUEUE_PFN: {
154*9bd8ac5cSAsias He 		struct virt_queue *queue;
155*9bd8ac5cSAsias He 		void *p;
156*9bd8ac5cSAsias He 
157*9bd8ac5cSAsias He 		assert(console_device.queue_selector < VIRTIO_CONSOLE_NUM_QUEUES);
158*9bd8ac5cSAsias He 
159*9bd8ac5cSAsias He 		queue		= &console_device.vqs[console_device.queue_selector];
160*9bd8ac5cSAsias He 		queue->pfn	= ioport__read32(data);
161*9bd8ac5cSAsias He 		p		= guest_flat_to_host(self, queue->pfn << 12);
162*9bd8ac5cSAsias He 
163*9bd8ac5cSAsias He 		vring_init(&queue->vring, VIRTIO_CONSOLE_QUEUE_SIZE, p, 4096);
164*9bd8ac5cSAsias He 
165*9bd8ac5cSAsias He 		break;
166*9bd8ac5cSAsias He 	}
167*9bd8ac5cSAsias He 	case VIRTIO_PCI_QUEUE_SEL:
168*9bd8ac5cSAsias He 		console_device.queue_selector	= ioport__read16(data);
169*9bd8ac5cSAsias He 		break;
170*9bd8ac5cSAsias He 	case VIRTIO_PCI_QUEUE_NOTIFY: {
171*9bd8ac5cSAsias He 		uint16_t queue_index;
172*9bd8ac5cSAsias He 		queue_index	= ioport__read16(data);
173*9bd8ac5cSAsias He 		virtio_console_handle_callback(self, queue_index);
174*9bd8ac5cSAsias He 		break;
175*9bd8ac5cSAsias He 	}
176*9bd8ac5cSAsias He 	case VIRTIO_PCI_STATUS:
177*9bd8ac5cSAsias He 		console_device.status		= ioport__read8(data);
178*9bd8ac5cSAsias He 		break;
179*9bd8ac5cSAsias He 	case VIRTIO_MSI_CONFIG_VECTOR:
180*9bd8ac5cSAsias He 		console_device.config_vector	= VIRTIO_MSI_NO_VECTOR;
181*9bd8ac5cSAsias He 		break;
182*9bd8ac5cSAsias He 	case VIRTIO_MSI_QUEUE_VECTOR:
183*9bd8ac5cSAsias He 		break;
184*9bd8ac5cSAsias He 	default:
185*9bd8ac5cSAsias He 		return false;
186*9bd8ac5cSAsias He 	};
187*9bd8ac5cSAsias He 
188*9bd8ac5cSAsias He 	return true;
189*9bd8ac5cSAsias He }
190*9bd8ac5cSAsias He 
191*9bd8ac5cSAsias He static struct ioport_operations virtio_console_io_ops = {
192*9bd8ac5cSAsias He 	.io_in	= virtio_console_pci_io_in,
193*9bd8ac5cSAsias He 	.io_out	= virtio_console_pci_io_out,
194*9bd8ac5cSAsias He };
195*9bd8ac5cSAsias He 
196*9bd8ac5cSAsias He #define PCI_VENDOR_ID_REDHAT_QUMRANET		0x1af4
197*9bd8ac5cSAsias He #define PCI_DEVICE_ID_VIRTIO_CONSOLE		0x1002
198*9bd8ac5cSAsias He #define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET	0x1af4
199*9bd8ac5cSAsias He #define PCI_SUBSYSTEM_ID_VIRTIO_CONSOLE		0x0003
200*9bd8ac5cSAsias He 
201*9bd8ac5cSAsias He static struct pci_device_header virtio_console_pci_device = {
202*9bd8ac5cSAsias He 	.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
203*9bd8ac5cSAsias He 	.device_id		= PCI_DEVICE_ID_VIRTIO_CONSOLE,
204*9bd8ac5cSAsias He 	.header_type		= PCI_HEADER_TYPE_NORMAL,
205*9bd8ac5cSAsias He 	.revision_id		= 0,
206*9bd8ac5cSAsias He 	.class			= (0x07 << 8) | (0x80 << 4) | (0x0 << 0),
207*9bd8ac5cSAsias He 	.subsys_vendor_id	= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
208*9bd8ac5cSAsias He 	.subsys_id		= PCI_SUBSYSTEM_ID_VIRTIO_CONSOLE,
209*9bd8ac5cSAsias He 	.bar[0]			= IOPORT_VIRTIO_CONSOLE | PCI_BASE_ADDRESS_SPACE_IO,
210*9bd8ac5cSAsias He 	.irq_pin		= 3,
211*9bd8ac5cSAsias He 	.irq_line		= VIRTIO_CONSOLE_IRQ,
212*9bd8ac5cSAsias He };
213*9bd8ac5cSAsias He 
214*9bd8ac5cSAsias He void virtio_console__init(struct kvm *self)
215*9bd8ac5cSAsias He {
216*9bd8ac5cSAsias He 	pci__register(&virtio_console_pci_device, PCI_VIRTIO_CONSOLE_DEVNUM);
217*9bd8ac5cSAsias He 	ioport__register(IOPORT_VIRTIO_CONSOLE, &virtio_console_io_ops, IOPORT_VIRTIO_CONSOLE_SIZE);
218*9bd8ac5cSAsias He }
219