Hi Andrew, On Mon, Oct 14, 2013 at 9:29 PM, Andrew Jones <drjones@xxxxxxxxxx> wrote: > This is a virtio version of hw/misc/debugexit and should evolve into a > virtio version of pc-testdev. pc-testdev uses the PC's ISA bus, whereas > this testdev can be plugged into a virtio-mmio transport, which is > needed for kvm-unit-tests/arm. virtio-testdev uses the virtio device > config space as a communication channel, and implements an RTAS-like > protocol through it allowing guests to execute commands. Only three > commands are currently implemented; > 1) VERSION: for version compatibility checks > 2) CLEAR: set all the config space back to zero > 3) EXIT: exit() from qemu with a status code How about adding RESET command to reset the VM? Regards, Anup > > Note, the protocol also requires all data passing through the config > space to be in little-endian. > > See [1] for an example of a driver for this device. > > [1] https://github.com/rhdrjones/kvm-unit-tests/blob/ff8df5378ffccfbdf25fe79241837e61eb2258e1/lib/virtio-testdev.c > > Signed-off-by: Andrew Jones <drjones@xxxxxxxxxx> > --- > default-configs/arm-softmmu.mak | 2 + > hw/virtio/Makefile.objs | 1 + > hw/virtio/virtio-testdev.c | 117 ++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 120 insertions(+) > create mode 100644 hw/virtio/virtio-testdev.c > > diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak > index ac0815d66310f..56f8086e61974 100644 > --- a/default-configs/arm-softmmu.mak > +++ b/default-configs/arm-softmmu.mak > @@ -80,3 +80,5 @@ CONFIG_VERSATILE_PCI=y > CONFIG_VERSATILE_I2C=y > > CONFIG_SDHCI=y > + > +CONFIG_VIRTIO_TESTDEV=y > diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs > index 1ba53d9cc316c..b3d16d522f54b 100644 > --- a/hw/virtio/Makefile.objs > +++ b/hw/virtio/Makefile.objs > @@ -3,6 +3,7 @@ common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o > common-obj-y += virtio-bus.o > common-obj-y += virtio-mmio.o > common-obj-$(CONFIG_VIRTIO_BLK_DATA_PLANE) += dataplane/ > +common-obj-$(CONFIG_VIRTIO_TESTDEV) += virtio-testdev.o > > obj-y += virtio.o virtio-balloon.o > obj-$(CONFIG_LINUX) += vhost.o > diff --git a/hw/virtio/virtio-testdev.c b/hw/virtio/virtio-testdev.c > new file mode 100644 > index 0000000000000..d6852d563702e > --- /dev/null > +++ b/hw/virtio/virtio-testdev.c > @@ -0,0 +1,117 @@ > +#include "hw/virtio/virtio-bus.h" > + > +#define VIRTIO_ID_TESTDEV 0xffff > + > +#define TYPE_VIRTIO_TESTDEV "virtio-testdev" > +#define VIRTIO_TESTDEV(obj) \ > + OBJECT_CHECK(VirtIOTestdev, (obj), TYPE_VIRTIO_TESTDEV) > + > +#define TESTDEV_MAJOR_VER 1 > +#define TESTDEV_MINOR_VER 1 > + > +#define CONFIG_SIZE 0x100 > + > +enum { > + VERSION = 1, > + CLEAR, > + EXIT, > +}; > + > +enum { TOKEN, NARGS, NRETS, ARG1, ARG2, ARG3, ARG4, }; > + > +#define RET1(nargs) (ARG1 + (nargs) + 0) > +#define RET2(nargs) (ARG1 + (nargs) + 1) > +#define RET3(nargs) (ARG1 + (nargs) + 2) > +#define RET4(nargs) (ARG1 + (nargs) + 3) > + > +#define calc_len(nargs, nrets) ((3 + (nargs) + (nrets)) * 4) > + > +typedef struct VirtIOTestdev { > + VirtIODevice parent_obj; > + uint8_t config[CONFIG_SIZE]; > + size_t len; /* currently used bytes */ > +} VirtIOTestdev; > + > +static void virtio_testdev_get_config(VirtIODevice *vdev, uint8_t *config_data) > +{ > + VirtIOTestdev *dev = VIRTIO_TESTDEV(vdev); > + memcpy(config_data, &dev->config[0], dev->len); > +} > + > +static void virtio_testdev_set_config(VirtIODevice *vdev, > + const uint8_t *config_data) > +{ > + VirtIOTestdev *dev = VIRTIO_TESTDEV(vdev); > + uint32_t *c32 = (uint32_t *)&dev->config[0]; > + uint32_t token, nargs, nrets; > + > + memcpy(c32, config_data, 32); /* assume write is in first 32 bytes, > + we can grab more later, if needed */ > + token = le32_to_cpu(c32[TOKEN]); > + nargs = le32_to_cpu(c32[NARGS]); > + nrets = le32_to_cpu(c32[NRETS]); > + > + if (!token) { > + return; > + } > + > + switch (token) { > + case VERSION: > + c32[RET1(nargs)] = > + cpu_to_le32((TESTDEV_MAJOR_VER << 16) | TESTDEV_MINOR_VER); > + break; > + case CLEAR: > + memset(c32, 0, CONFIG_SIZE); > + break; > + case EXIT: > + exit((le32_to_cpu(c32[ARG1]) << 1) | 1); > + default: > + break; > + } > + > + c32[TOKEN] = 0; > + dev->len = calc_len(nargs, nrets); > +} > + > +static uint32_t virtio_testdev_get_features(VirtIODevice *vdev, uint32_t f) > +{ > + return f; > +} > + > +static int virtio_testdev_init(VirtIODevice *vdev) > +{ > + virtio_init(vdev, "virtio-testdev", VIRTIO_ID_TESTDEV, CONFIG_SIZE); > + return 0; > +} > + > +static int virtio_testdev_exit(DeviceState *qdev) > +{ > + virtio_cleanup(VIRTIO_DEVICE(qdev)); > + return 0; > +} > + > +static void virtio_testdev_class_init(ObjectClass *klass, void *data) > +{ > + DeviceClass *dc = DEVICE_CLASS(klass); > + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); > + dc->exit = virtio_testdev_exit; > + set_bit(DEVICE_CATEGORY_MISC, dc->categories); > + vdc->init = virtio_testdev_init; > + vdc->get_config = virtio_testdev_get_config; > + vdc->set_config = virtio_testdev_set_config; > + vdc->get_features = virtio_testdev_get_features; > +} > + > +static const TypeInfo virtio_testdev_info = { > + .name = TYPE_VIRTIO_TESTDEV, > + .parent = TYPE_VIRTIO_DEVICE, > + .instance_size = sizeof(VirtIOTestdev), > + .class_init = virtio_testdev_class_init, > +}; > + > +static void virtio_register_types(void) > +{ > + type_register_static(&virtio_testdev_info); > +} > + > +type_init(virtio_register_types) > -- > 1.8.3.1 > > _______________________________________________ > kvmarm mailing list > kvmarm@xxxxxxxxxxxxxxxxxxxxx > https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm _______________________________________________ kvmarm mailing list kvmarm@xxxxxxxxxxxxxxxxxxxxx https://lists.cs.columbia.edu/cucslists/listinfo/kvmarm