I really worry about us introducing so many of these one-off paravirtual devices.
I would much prefer that you look at doing this as an extension to the ivshmem device as it already has this sort of scope. You should be able to do this by just extending the size of bar 1 and using a well known guest id.
Regards, Anthony Liguori On 12/05/2011 04:23 PM, Lluís Vilanova wrote:
Uses a virtual device to proxy uses of the backdoor communication channel to the user-provided code. Signed-off-by: Lluís Vilanova<vilan...@ac.upc.edu> --- Makefile.objs | 1 backdoor/qemu/softmmu.c | 186 +++++++++++++++++++++++++++++++++++++++++++++++ hw/pci.h | 1 3 files changed, 188 insertions(+), 0 deletions(-) create mode 100644 backdoor/qemu/softmmu.c diff --git a/Makefile.objs b/Makefile.objs index 9784441..a45ff56 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -401,6 +401,7 @@ $(trace-obj-y): $(GENERATED_HEADERS) # backdoor backdoor-nested-$(CONFIG_USER_ONLY) += user.o +backdoor-nested-$(CONFIG_SOFTMMU) += softmmu.o backdoor-obj-y += $(addprefix backdoor/qemu/, $(backdoor-nested-y)) diff --git a/backdoor/qemu/softmmu.c b/backdoor/qemu/softmmu.c new file mode 100644 index 0000000..9cde59f --- /dev/null +++ b/backdoor/qemu/softmmu.c @@ -0,0 +1,186 @@ +/* + * QEMU-side management of backdoor channels in softmmu emulation. + * + * Copyright (C) 2011 Lluís Vilanova<vilan...@ac.upc.edu> + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "hw/pci.h" +#include "backdoor/qemu/qemu-backdoor.h" + + +#define PAGE_SIZE TARGET_PAGE_SIZE + + +typedef struct BackdoorState +{ + PCIDevice dev; + + uint8_t pages; + uint64_t size; + + union + { + uint64_t v; + char a[8]; + } c_size; + union + { + uint64_t v; + uint8_t a[8]; + } c_cmd; + + void *data_ptr; + MemoryRegion data; + MemoryRegion control; +} BackdoorState; + + +static uint64_t backdoor_control_io_read(void *opaque, target_phys_addr_t addr, unsigned size) +{ + BackdoorState *s = opaque; + + /* c_size already has target endianess */ + + switch (size) { + case 1: + { + uint8_t *res = (uint8_t*)&s->c_size.a[addr % sizeof(uint64_t)]; + return *res; + } + case 2: + { + uint16_t *res = (uint16_t*)&s->c_size.a[addr % sizeof(uint64_t)]; + return *res; + } + case 4: + { + uint32_t *res = (uint32_t*)&s->c_size.a[addr % sizeof(uint64_t)]; + return *res; + } + case 8: + { + uint64_t *res = (uint64_t*)&s->c_size.a[addr % sizeof(uint64_t)]; + return *res; + } + default: + fprintf(stderr, "error: backdoor: Unexpected read of size %d\n", size); + abort(); + } +} + +static void backdoor_control_io_write(void *opaque, target_phys_addr_t addr, uint64_t data, unsigned size) +{ + BackdoorState *s = opaque; + + /* c_cmd will have target endianess (left up to the user) */ + + switch (size) { + case 1: + { + uint8_t *res = (uint8_t*)&s->c_cmd.a[addr % sizeof(uint64_t)]; + *res = (uint8_t)data; + break; + } + case 2: + { + uint16_t *res = (uint16_t*)&s->c_cmd.a[addr % sizeof(uint64_t)]; + *res = (uint16_t)data; + break; + } + case 4: + { + uint32_t *res = (uint32_t*)&s->c_cmd.a[addr % sizeof(uint64_t)]; + *res = (uint32_t)data; + break; + } + case 8: + { + uint64_t *res = (uint64_t*)&s->c_cmd.a[addr % sizeof(uint64_t)]; + *res = (uint64_t)data; + break; + } + default: + fprintf(stderr, "error: backdoor: Unexpected write of size %d\n", size); + abort(); + } + + if ((addr + size) % sizeof(s->c_cmd.v) == 0) { + qemu_backdoor(s->c_cmd.v, s->data_ptr); + } +} + +static const MemoryRegionOps backdoor_control_ops = { + .read = backdoor_control_io_read, + .write = backdoor_control_io_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + + +static int backdoor_init(PCIDevice *dev) +{ + BackdoorState *s = DO_UPCAST(BackdoorState, dev, dev); + + if (s->pages< 1) { + fprintf(stderr, "error: backdoor: " + "the data channel must have one or more pages\n"); + return -1; + } + s->size = s->pages * PAGE_SIZE; + s->c_size.v = tswap64(s->size); + + pci_set_word(s->dev.config + PCI_COMMAND, + PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + + memory_region_init_io(&s->control,&backdoor_control_ops, s, + "backdoor.control", PAGE_SIZE); + pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,&s->control); + + memory_region_init_ram(&s->data,&s->dev.qdev, + "backdoor.data", s->c_size.v); + pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY,&s->data); + s->data_ptr = qemu_get_ram_ptr(s->data.ram_addr); + + qemu_backdoor_init(s->c_size.v); + + return 0; +} + +static int backdoor_fini(PCIDevice *dev) +{ + BackdoorState *s = DO_UPCAST(BackdoorState, dev, dev); + + memory_region_destroy(&s->data); + memory_region_destroy(&s->control); + + return 0; +} + + +static PCIDeviceInfo backdoor_info = { + .qdev.name = "backdoor", + .qdev.desc = "Backdoor communication channel", + .qdev.size = sizeof(BackdoorState), + .init = backdoor_init, + .exit = backdoor_fini, + .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, + .device_id = PCI_DEVICE_ID_BACKDOOR, + .class_id = PCI_CLASS_MEMORY_RAM, + .qdev.props = (Property[]) { + DEFINE_PROP_UINT8("pages", BackdoorState, pages, 1), + DEFINE_PROP_END_OF_LIST(), + } +}; + +static void backdoor_register_device(void) +{ + pci_qdev_register(&backdoor_info); +} + +device_init(backdoor_register_device) diff --git a/hw/pci.h b/hw/pci.h index 625e717..e7dc3cb 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -75,6 +75,7 @@ #define PCI_DEVICE_ID_VIRTIO_BLOCK 0x1001 #define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002 #define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003 +#define PCI_DEVICE_ID_BACKDOOR 0x1004 #define FMT_PCIBUS PRIx64