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 | 124 +++++++++++++++++++++++++++++++++++++++++++++++ hw/pci.h | 1 3 files changed, 126 insertions(+), 0 deletions(-) create mode 100644 backdoor/qemu/softmmu.c diff --git a/Makefile.objs b/Makefile.objs index d39074d..5f54d10 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -398,6 +398,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..fdd3a25 --- /dev/null +++ b/backdoor/qemu/softmmu.c @@ -0,0 +1,124 @@ +/* + * 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 +#define CTRL_BYTES sizeof(uint64_t) + + +typedef struct State +{ + PCIDevice dev; + + uint8_t pages; + uint64_t size; + + uint64_t cmd; + + void *data_ptr; + MemoryRegion data; + MemoryRegion control; +} State; + + +static uint64_t control_io_read(void *opaque, target_phys_addr_t addr, unsigned size) +{ + State *s = opaque; + + uint64_t res = ldq_p(&s->size); + uint8_t *resb = (uint8_t*)&res; + return resb[addr % CTRL_BYTES]; +} + +static void control_io_write(void *opaque, target_phys_addr_t addr, uint64_t data, unsigned size) +{ + State *s = opaque; + + uint8_t *cmdb = (uint8_t*)&s->cmd; + cmdb[addr % CTRL_BYTES] = (uint8_t)data; + + if ((addr + size) % CTRL_BYTES == 0) { + qemu_backdoor(ldq_p(&s->cmd), s->data_ptr); + } +} + +static const MemoryRegionOps control_ops = { + .read = control_io_read, + .write = control_io_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + + +static int init(PCIDevice *dev) +{ + State *s = DO_UPCAST(State, 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; + + pci_set_word(s->dev.config + PCI_COMMAND, + PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + + memory_region_init_io(&s->control, &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->size); + 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->size); + + return 0; +} + +static int fini(PCIDevice *dev) +{ + State *s = DO_UPCAST(State, dev, dev); + + memory_region_destroy(&s->data); + memory_region_destroy(&s->control); + + return 0; +} + + +static PCIDeviceInfo info = { + .qdev.name = "backdoor", + .qdev.desc = "Backdoor communication channel", + .qdev.size = sizeof(State), + .init = init, + .exit = 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", State, pages, 1), + DEFINE_PROP_END_OF_LIST(), + } +}; + +static void register_device(void) +{ + pci_qdev_register(&info); +} + +device_init(register_device) diff --git a/hw/pci.h b/hw/pci.h index 86a81c8..4d7d161 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