1 #include "kvm/virtio-console.h"
2 #include "kvm/virtio-pci-dev.h"
3 #include "kvm/disk-image.h"
4 #include "kvm/virtio.h"
5 #include "kvm/ioport.h"
11 #include "kvm/threadpool.h"
13 #include "kvm/guest_compat.h"
14 #include "kvm/virtio-pci.h"
16 #include <linux/virtio_console.h>
17 #include <linux/virtio_ring.h>
18 #include <linux/virtio_blk.h>
21 #include <sys/types.h>
28 #define VIRTIO_CONSOLE_QUEUE_SIZE 128
29 #define VIRTIO_CONSOLE_NUM_QUEUES 2
30 #define VIRTIO_CONSOLE_RX_QUEUE 0
31 #define VIRTIO_CONSOLE_TX_QUEUE 1
34 pthread_mutex_t mutex
;
36 struct virtio_pci vpci
;
37 struct virt_queue vqs
[VIRTIO_CONSOLE_NUM_QUEUES
];
38 struct virtio_console_config config
;
42 struct thread_pool__job jobs
[VIRTIO_CONSOLE_NUM_QUEUES
];
45 static struct con_dev cdev
= {
46 .mutex
= PTHREAD_MUTEX_INITIALIZER
,
56 * Interrupts are injected for hvc0 only.
58 static void virtio_console__inject_interrupt_callback(struct kvm
*kvm
, void *param
)
60 struct iovec iov
[VIRTIO_CONSOLE_QUEUE_SIZE
];
61 struct virt_queue
*vq
;
66 mutex_lock(&cdev
.mutex
);
70 if (term_readable(CONSOLE_VIRTIO
) && virt_queue__available(vq
)) {
71 head
= virt_queue__get_iov(vq
, iov
, &out
, &in
, kvm
);
72 len
= term_getc_iov(CONSOLE_VIRTIO
, iov
, in
);
73 virt_queue__set_used_elem(vq
, head
, len
);
74 virtio_pci__signal_vq(kvm
, &cdev
.vpci
, vq
- cdev
.vqs
);
77 mutex_unlock(&cdev
.mutex
);
80 void virtio_console__inject_interrupt(struct kvm
*kvm
)
82 thread_pool__do_job(&cdev
.jobs
[VIRTIO_CONSOLE_RX_QUEUE
]);
85 static void virtio_console_handle_callback(struct kvm
*kvm
, void *param
)
87 struct iovec iov
[VIRTIO_CONSOLE_QUEUE_SIZE
];
88 struct virt_queue
*vq
;
96 * The current Linux implementation polls for the buffer
97 * to be used, rather than waiting for an interrupt.
98 * So there is no need to inject an interrupt for the tx path.
101 while (virt_queue__available(vq
)) {
102 head
= virt_queue__get_iov(vq
, iov
, &out
, &in
, kvm
);
103 len
= term_putc_iov(CONSOLE_VIRTIO
, iov
, out
);
104 virt_queue__set_used_elem(vq
, head
, len
);
109 static void set_config(struct kvm
*kvm
, void *dev
, u8 data
, u32 offset
)
111 struct con_dev
*cdev
= dev
;
113 ((u8
*)(&cdev
->config
))[offset
] = data
;
116 static u8
get_config(struct kvm
*kvm
, void *dev
, u32 offset
)
118 struct con_dev
*cdev
= dev
;
120 return ((u8
*)(&cdev
->config
))[offset
];
123 static u32
get_host_features(struct kvm
*kvm
, void *dev
)
128 static void set_guest_features(struct kvm
*kvm
, void *dev
, u32 features
)
133 static int init_vq(struct kvm
*kvm
, void *dev
, u32 vq
, u32 pfn
)
135 struct virt_queue
*queue
;
138 assert(vq
< VIRTIO_CONSOLE_NUM_QUEUES
);
140 compat__remove_message(cdev
.compat_id
);
142 queue
= &cdev
.vqs
[vq
];
144 p
= guest_pfn_to_host(kvm
, queue
->pfn
);
146 vring_init(&queue
->vring
, VIRTIO_CONSOLE_QUEUE_SIZE
, p
, VIRTIO_PCI_VRING_ALIGN
);
148 if (vq
== VIRTIO_CONSOLE_TX_QUEUE
)
149 thread_pool__init_job(&cdev
.jobs
[vq
], kvm
, virtio_console_handle_callback
, queue
);
150 else if (vq
== VIRTIO_CONSOLE_RX_QUEUE
)
151 thread_pool__init_job(&cdev
.jobs
[vq
], kvm
, virtio_console__inject_interrupt_callback
, queue
);
156 static int notify_vq(struct kvm
*kvm
, void *dev
, u32 vq
)
158 struct con_dev
*cdev
= dev
;
160 thread_pool__do_job(&cdev
->jobs
[vq
]);
165 static int get_pfn_vq(struct kvm
*kvm
, void *dev
, u32 vq
)
167 struct con_dev
*cdev
= dev
;
169 return cdev
->vqs
[vq
].pfn
;
172 static int get_size_vq(struct kvm
*kvm
, void *dev
, u32 vq
)
174 return VIRTIO_CONSOLE_QUEUE_SIZE
;
177 void virtio_console__init(struct kvm
*kvm
)
179 virtio_pci__init(kvm
, &cdev
.vpci
, &cdev
, PCI_DEVICE_ID_VIRTIO_CONSOLE
, VIRTIO_ID_CONSOLE
);
180 cdev
.vpci
.ops
= (struct virtio_pci_ops
) {
181 .set_config
= set_config
,
182 .get_config
= get_config
,
183 .get_host_features
= get_host_features
,
184 .set_guest_features
= set_guest_features
,
186 .notify_vq
= notify_vq
,
187 .get_pfn_vq
= get_pfn_vq
,
188 .get_size_vq
= get_size_vq
,
191 cdev
.compat_id
= compat__add_message("virtio-console device was not detected",
192 "While you have requested a virtio-console device, "
193 "the guest kernel didn't seem to detect it.\n"
194 "Please make sure that the kernel was compiled"
195 "with CONFIG_VIRTIO_CONSOLE.");