mirror of
https://github.com/clearlinux/kvmtool.git
synced 2026-09-06 05:31:50 +00:00
kvm: Virtio block device emulation
This patch implements a rough first version of virtio block device emulation. You can enable it with the '--enable-virtio' command line option. We're still missing virtio queue handling so enabling virtio will cause a guest kernel to hang. Signed-off-by: Pekka Enberg <penberg@kernel.org>
This commit is contained in:
committed by
Will Deacon
parent
c9bb7f2059
commit
8b1ff07e1f
+28
-6
@@ -2,9 +2,10 @@
|
||||
|
||||
#include "kvm/virtio_pci.h"
|
||||
#include "kvm/ioport.h"
|
||||
#include "kvm/kvm.h"
|
||||
#include "kvm/pci.h"
|
||||
|
||||
#define VIRTIO_PCI_IOPORT_SIZE 24
|
||||
#define VIRTIO_BLK_IRQ 14
|
||||
|
||||
struct device {
|
||||
uint32_t guest_features;
|
||||
@@ -19,13 +20,22 @@ static bool blk_virtio_in(struct kvm *self, uint16_t port, void *data, int size,
|
||||
|
||||
offset = port - IOPORT_VIRTIO;
|
||||
|
||||
/* XXX: Let virtio block device handle this */
|
||||
if (offset >= VIRTIO_PCI_CONFIG_NOMSI)
|
||||
return true;
|
||||
|
||||
switch (offset) {
|
||||
case VIRTIO_PCI_HOST_FEATURES:
|
||||
ioport__write32(data, 0x00);
|
||||
break;
|
||||
case VIRTIO_PCI_GUEST_FEATURES:
|
||||
return false;
|
||||
case VIRTIO_PCI_QUEUE_PFN:
|
||||
ioport__write32(data, 0x00);
|
||||
break;
|
||||
case VIRTIO_PCI_QUEUE_NUM:
|
||||
ioport__write16(data, 0x10);
|
||||
break;
|
||||
case VIRTIO_PCI_QUEUE_SEL:
|
||||
case VIRTIO_PCI_QUEUE_NOTIFY:
|
||||
return false;
|
||||
@@ -33,6 +43,9 @@ static bool blk_virtio_in(struct kvm *self, uint16_t port, void *data, int size,
|
||||
ioport__write8(data, device.status);
|
||||
break;
|
||||
case VIRTIO_PCI_ISR:
|
||||
ioport__write8(data, 0x1);
|
||||
kvm__irq_line(self, VIRTIO_BLK_IRQ, 0);
|
||||
return true;
|
||||
case VIRTIO_MSI_CONFIG_VECTOR:
|
||||
default:
|
||||
return false;
|
||||
@@ -41,22 +54,28 @@ static bool blk_virtio_in(struct kvm *self, uint16_t port, void *data, int size,
|
||||
return true;
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static bool blk_virtio_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count)
|
||||
{
|
||||
unsigned long offset;
|
||||
|
||||
offset = port - IOPORT_VIRTIO;
|
||||
|
||||
/* XXX: Let virtio block device handle this */
|
||||
if (offset >= VIRTIO_PCI_CONFIG_NOMSI)
|
||||
return true;
|
||||
|
||||
switch (offset) {
|
||||
case VIRTIO_PCI_GUEST_FEATURES:
|
||||
device.guest_features = ioport__read32(data);
|
||||
break;
|
||||
case VIRTIO_PCI_QUEUE_PFN:
|
||||
return true;
|
||||
case VIRTIO_PCI_QUEUE_SEL:
|
||||
case VIRTIO_PCI_QUEUE_NOTIFY:
|
||||
return false;
|
||||
return true;
|
||||
case VIRTIO_PCI_QUEUE_NOTIFY: {
|
||||
kvm__irq_line(self, VIRTIO_BLK_IRQ, 1);
|
||||
return true;
|
||||
}
|
||||
case VIRTIO_PCI_STATUS:
|
||||
device.status = ioport__read8(data);
|
||||
break;
|
||||
@@ -88,11 +107,14 @@ static struct pci_device_header blk_virtio_pci_device = {
|
||||
.subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
|
||||
.subsys_id = PCI_SUBSYSTEM_ID_VIRTIO_BLK,
|
||||
.bar[0] = IOPORT_VIRTIO | PCI_BASE_ADDRESS_SPACE_IO,
|
||||
/* XXX: Is this IRQ setup OK? */
|
||||
.irq_pin = 1,
|
||||
.irq_line = VIRTIO_BLK_IRQ,
|
||||
};
|
||||
|
||||
void blk_virtio__init(void)
|
||||
{
|
||||
pci__register(&blk_virtio_pci_device, 1);
|
||||
|
||||
ioport__register(IOPORT_VIRTIO, &blk_virtio_io_ops, VIRTIO_PCI_IOPORT_SIZE);
|
||||
ioport__register(IOPORT_VIRTIO, &blk_virtio_io_ops, 256);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,11 @@ static inline uint8_t ioport__read8(uint8_t *data)
|
||||
return *data;
|
||||
}
|
||||
|
||||
static inline uint16_t ioport__read16(uint16_t *data)
|
||||
{
|
||||
return *data;
|
||||
}
|
||||
|
||||
static inline uint32_t ioport__read32(uint32_t *data)
|
||||
{
|
||||
return *data;
|
||||
@@ -32,6 +37,11 @@ static inline void ioport__write8(uint8_t *data, uint8_t value)
|
||||
*data = value;
|
||||
}
|
||||
|
||||
static inline void ioport__write16(uint16_t *data, uint16_t value)
|
||||
{
|
||||
*data = value;
|
||||
}
|
||||
|
||||
static inline void ioport__write32(uint32_t *data, uint32_t value)
|
||||
{
|
||||
*data = value;
|
||||
|
||||
@@ -40,6 +40,7 @@ bool kvm__load_kernel(struct kvm *kvm, const char *kernel_filename,
|
||||
void kvm__reset_vcpu(struct kvm *self);
|
||||
void kvm__setup_mem(struct kvm *self);
|
||||
void kvm__run(struct kvm *self);
|
||||
void kvm__irq_line(struct kvm *self, int irq, int level);
|
||||
bool kvm__emulate_io(struct kvm *self, uint16_t port, void *data, int direction, int size, uint32_t count);
|
||||
bool kvm__emulate_mmio(struct kvm *self, uint64_t phys_addr, uint8_t *data, uint32_t len, uint8_t is_write);
|
||||
|
||||
|
||||
@@ -49,4 +49,8 @@
|
||||
/* A 16-bit vector for selected queue notifications. */
|
||||
#define VIRTIO_MSI_QUEUE_VECTOR 22
|
||||
|
||||
/* Config space size */
|
||||
#define VIRTIO_PCI_CONFIG_NOMSI 20
|
||||
#define VIRTIO_PCI_CONFIG_MSI 24
|
||||
|
||||
#endif /* _LINUX_VIRTIO_PCI_H */
|
||||
|
||||
@@ -611,6 +611,21 @@ void kvm__run(struct kvm *self)
|
||||
die_perror("KVM_RUN failed");
|
||||
}
|
||||
|
||||
void kvm__irq_line(struct kvm *self, int irq, int level)
|
||||
{
|
||||
struct kvm_irq_level irq_level;
|
||||
|
||||
irq_level = (struct kvm_irq_level) {
|
||||
{
|
||||
.irq = irq,
|
||||
},
|
||||
.level = level,
|
||||
};
|
||||
|
||||
if (ioctl(self->vm_fd, KVM_IRQ_LINE, &irq_level) < 0)
|
||||
die_perror("KVM_IRQ_LINE failed");
|
||||
}
|
||||
|
||||
static void print_dtable(const char *name, struct kvm_dtable *dtable)
|
||||
{
|
||||
printf(" %s %016" PRIx64 " %08" PRIx16 "\n",
|
||||
|
||||
@@ -51,6 +51,7 @@ int main(int argc, char *argv[])
|
||||
const char *kernel_cmdline = NULL;
|
||||
const char *kvm_dev = "/dev/kvm";
|
||||
unsigned long ram_size = 64UL << 20;
|
||||
bool enable_virtio = false;
|
||||
bool single_step = false;
|
||||
int i;
|
||||
|
||||
@@ -72,6 +73,9 @@ int main(int argc, char *argv[])
|
||||
} else if (option_matches(argv[i], "--single-step")) {
|
||||
single_step = true;
|
||||
continue;
|
||||
} else if (option_matches(argv[i], "--enable-virtio")) {
|
||||
enable_virtio = true;
|
||||
continue;
|
||||
} else if (option_matches(argv[i], "--mem=")) {
|
||||
unsigned long val = atol(&argv[i][6]) << 20;
|
||||
if (val < ram_size)
|
||||
@@ -117,7 +121,9 @@ int main(int argc, char *argv[])
|
||||
|
||||
early_printk__init();
|
||||
pci__init();
|
||||
blk_virtio__init();
|
||||
|
||||
if (enable_virtio)
|
||||
blk_virtio__init();
|
||||
|
||||
for (;;) {
|
||||
kvm__run(kvm);
|
||||
|
||||
Reference in New Issue
Block a user