From 7fe765d123c9ade3613f6128ae86a3be7a602d60 Mon Sep 17 00:00:00 2001 From: Izik Eidus Date: Sat, 21 Nov 2009 22:43:28 +0200 Subject: vdesktop: add memslot support Signed-off-by: Izik Eidus --- qemu/configure | 2 +- qemu/hw/pc.c | 19 ++- qemu/hw/pc.h | 11 +- qemu/hw/qxl.c | 285 +++++++++++++++++++++++++++++++++++++++++--- qemu/hw/qxl_dev.h | 16 ++- qemu/hw/qxl_interface.h | 24 +++- qemu/hw/qxl_native_worker.c | 139 ++++++++++++++++++++- 7 files changed, 471 insertions(+), 25 deletions(-) diff --git a/qemu/configure b/qemu/configure index ed5757db..5c3d36f8 100755 --- a/qemu/configure +++ b/qemu/configure @@ -1220,7 +1220,7 @@ fi ########################################## # spice probe if test "$spice" = "yes" ; then - `pkg-config --atleast-version=0.3.0 spice` || spice="no" + `pkg-config --atleast-version=0.5.1 spice` || spice="no" fi if test "$spice" = "yes" ; then cat > $TMPC << EOF diff --git a/qemu/hw/pc.c b/qemu/hw/pc.c index f87fa226..3fe5bf72 100644 --- a/qemu/hw/pc.c +++ b/qemu/hw/pc.c @@ -829,6 +829,7 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size, int ret, linux_boot, i; ram_addr_t ram_addr, vga_ram_addr, bios_offset, vga_bios_offset; ram_addr_t below_4g_mem_size, above_4g_mem_size = 0; + ram_addr_t below_4g_ram_addr, above_4g_ram_addr = 0; int bios_size, isa_bios_size, vga_bios_size, opt_rom_offset; int pci_option_rom_offset; PCIBus *pci_bus; @@ -876,6 +877,7 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size, */ ram_addr = qemu_ram_alloc(0x100000 - 0xa0000); ram_addr = qemu_ram_alloc(below_4g_mem_size - 0x100000); + below_4g_ram_addr = ram_addr; cpu_register_physical_memory(0x100000, below_4g_mem_size - 0x100000, ram_addr); @@ -883,6 +885,7 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size, /* above 4giga memory allocation */ if (above_4g_mem_size > 0) { ram_addr = qemu_ram_alloc(above_4g_mem_size); + above_4g_ram_addr = ram_addr; if (hpagesize) { if (ram_addr & (hpagesize-1)) { unsigned long aligned_addr; @@ -1037,9 +1040,23 @@ static void pc_init1(ram_addr_t ram_size, int vga_ram_size, isa_vga_init(ds, phys_ram_base + vga_ram_addr, vga_ram_addr, vga_ram_size); for (i = 0; i < num_qxl_device; i++) { + QXLAddressRange address_ranges[2]; + uint32_t qxl_total_mem_size = qxl_get_total_mem_size(qxl_ram_size); ram_addr_t qxl_ram = qemu_ram_alloc(qxl_total_mem_size); - qxl_init(pci_bus, phys_ram_base + qxl_ram, qxl_ram, qxl_total_mem_size, qxl_ram_size); + + address_ranges[0].phys_start = 0x100000; + address_ranges[0].phys_end = 0x100000 + below_4g_mem_size; + address_ranges[0].virt_start = below_4g_ram_addr + phys_ram_base; + address_ranges[0].virt_end = address_ranges[1].virt_start + below_4g_mem_size; + + address_ranges[1].phys_start = 0x100000000ULL; + address_ranges[1].phys_end = 0x100000000ULL + above_4g_mem_size; + address_ranges[1].virt_start = above_4g_ram_addr + phys_ram_base; + address_ranges[1].virt_end = address_ranges[2].virt_start + above_4g_mem_size; + + qxl_init(pci_bus, phys_ram_base + qxl_ram, qxl_ram, qxl_total_mem_size, qxl_ram_size, + address_ranges, 2); } #endif #ifdef CONFIG_VMWARE diff --git a/qemu/hw/pc.h b/qemu/hw/pc.h index ad156f13..072c9b0c 100644 --- a/qemu/hw/pc.h +++ b/qemu/hw/pc.h @@ -172,9 +172,18 @@ extern int using_qxl; extern int num_qxl_device; extern uint32_t qxl_ram_size; +typedef struct QXLAddressRange { + target_phys_addr_t phys_start; + target_phys_addr_t phys_end; + unsigned long virt_start; + unsigned long virt_end; +} QXLAddressRange; + void qxl_init(PCIBus *bus, uint8_t *vram, unsigned long vram_offset, - uint32_t vram_size, uint32_t in_ram_size); + uint32_t vram_size, uint32_t in_ram_size, + QXLAddressRange *address_ranges, + uint8_t num_ranges); void qxl_init_display(DisplayState *ds); int qxl_vga_touch(void); diff --git a/qemu/hw/qxl.c b/qemu/hw/qxl.c index c3322b5c..e869c812 100644 --- a/qemu/hw/qxl.c +++ b/qemu/hw/qxl.c @@ -30,6 +30,11 @@ exit(-1); \ } +#define PANIC_ON(x) if ((x)) { \ + printf("%s: PANIC %s failed\n", __FUNCTION__, #x); \ + exit(-1); \ +} + #undef ALIGN #define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1)) @@ -80,6 +85,18 @@ typedef struct __attribute__ ((__packed__)) PCIConf_s /*little-endian*/ { uint8_t max_letency; } PCIConf; +#define NUM_MEMSLOTS 256 +#define MEMSLOT_GENERATION_BITS 8 +#define MEMSLOT_SLOT_BITS 8 + +typedef struct MemSlot { + int active; + unsigned long virt_start; + unsigned long virt_end; + int64_t address_delta; + uint8_t generation; +} MemSlot; + enum { QXL_MODE_UNDEFINED, QXL_MODE_VGA, @@ -99,6 +116,11 @@ typedef struct QXLState { uint32_t ram_size; uint64_t ram_phys_addr; + QXLAddressRange *address_ranges; + uint8_t num_ranges; + + MemSlot mem_slots[NUM_MEMSLOTS]; + uint8_t *vram; unsigned long vram_offset; uint32_t vram_size; @@ -323,6 +345,13 @@ static void set_dreaw_area(PCIQXLDevice *d, QXLDevInfo *info) info->draw_area.heigth = info->y_res; } +static void _qxl_get_init_info(PCIQXLDevice *d, QXLDevInitInfo *info) +{ + info->memslot_gen_bits = MEMSLOT_GENERATION_BITS; + info->memslot_id_bits = MEMSLOT_SLOT_BITS; + info->num_memslots = NUM_MEMSLOTS; +} + static void _qxl_get_info(PCIQXLDevice *d, QXLDevInfo *info) { QXLState *state = &d->state; @@ -336,9 +365,6 @@ static void _qxl_get_info(PCIQXLDevice *d, QXLDevInfo *info) info->bits = qxl_vga.ds->depth; info->use_hardware_cursor = FALSE; - info->phys_start = 0; - info->phys_end = ~info->phys_start; - info->phys_delta = 0; set_dreaw_area(d, info); return; } @@ -350,9 +376,6 @@ static void _qxl_get_info(PCIQXLDevice *d, QXLDevInfo *info) info->bits = mode->bits; info->use_hardware_cursor = TRUE; - info->phys_start = (unsigned long)state->ram_start + state->rom->pages_offset; - info->phys_end = (unsigned long)state->ram_start + state->ram_size; - info->phys_delta = (long)state->ram_start - state->ram_phys_addr; set_dreaw_area(d, info); } @@ -584,6 +607,50 @@ static void qxl_notify_mode_change(PCIQXLDevice *d) #endif } +static void qxl_create_host_memslot(PCIQXLDevice *d) +{ + MemSlot *device_slot; + QXLDevMemSlot qxl_dev_slot; + + printf("%s\n", __FUNCTION__); + + PANIC_ON(d->state.mem_slots[0].active); + + device_slot = &d->state.mem_slots[0]; + device_slot->active = TRUE; + device_slot->address_delta = 0; + device_slot->virt_start = 0; + device_slot->virt_end = ~(unsigned long)0; + + qxl_dev_slot.slot_id = 0; + qxl_dev_slot.addr_delta = device_slot->address_delta; + qxl_dev_slot.virt_start = device_slot->virt_start; + qxl_dev_slot.virt_end = device_slot->virt_end; + qxl_dev_slot.generation = device_slot->generation = 0; + + d->worker->add_memslot(d->worker, &qxl_dev_slot); +} + +static void qxl_init_memslots(PCIQXLDevice *d) +{ + int i; + + for (i = 1; i < NUM_MEMSLOTS; ++i) { + d->state.mem_slots[i].generation = 1; + } +} + +static void qxl_reset_memslots(PCIQXLDevice *d) +{ + int i; + + for (i = 0; i < NUM_MEMSLOTS; ++i) { + d->state.mem_slots[i].active = FALSE; + } + + d->worker->reset_memslots(d->worker); +} + static void qxl_set_mode(PCIQXLDevice *d, uint32_t mode) { if (mode > sizeof(qxl_modes) / sizeof(QXLMode)) { @@ -656,6 +723,7 @@ static void qxl_reset(PCIQXLDevice *d) printf("%s\n", __FUNCTION__); qxl_detach(d); qxl_reset_state(d); + if (QXL_SHARED_VGA_MODE || !d->id) { qxl_enter_vga_mode(d); d->worker->attach(d->worker); @@ -666,6 +734,13 @@ static void qxl_reset(PCIQXLDevice *d) qemu_set_irq(d->pci_dev.irq[0], irq_level(d)); } +static void qxl_hard_reset(PCIQXLDevice *d) +{ + qxl_reset(d); + qxl_reset_memslots(d); + qxl_create_host_memslot(d); +} + static inline void vdi_port_set_dirty(PCIVDIPortDevice *d, void *start, uint32_t length) { ram_addr_t addr = (ram_addr_t)start - (ram_addr_t)d->ram + d->ram_offset; @@ -905,6 +980,141 @@ static void vdi_port_dev_notify(PCIVDIPortDevice *d) #endif } +static inline int in_range_start(unsigned long start, unsigned long range_start, + unsigned long range_end) { + if (start >= range_start && start < range_end) { + return TRUE; + } + + return FALSE; +} + +static inline int in_range_end(unsigned long end, unsigned long range_start, + unsigned long range_end) { + if (end > range_start && end <= range_end) { + return TRUE; + } + + return FALSE; +} + +static inline int address_in_range(unsigned long start, unsigned long end, QXLAddressRange *range) +{ + if (in_range_start(start, range->phys_start, range->phys_end) && + in_range_end(end, start, range->phys_end)) { + return TRUE; + } + return FALSE; +} + +static inline int is_intersecting_memslot(MemSlot *slot, unsigned long vstart, unsigned long vend) +{ + return vstart < slot->virt_end && vend > slot->virt_start; +} + +static void qxl_check_memslot_range(PCIQXLDevice *d, unsigned long virt_start, + unsigned long virt_end) +{ + int x; + MemSlot *slot; + + for (x = 1; x < NUM_MEMSLOTS; ++x) { + slot = &d->state.mem_slots[x]; + + if (slot->active) { + PANIC_ON(is_intersecting_memslot(slot, virt_start, virt_end)); + } + } +} + +static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id) +{ + QXLMemSlot *slot; + QXLDevMemSlot qxl_dev_slot; + MemSlot *device_slot; + uint64_t start; + uint64_t end; + uint64_t start_offset; + uint64_t end_offset; + unsigned long new_virt_start; + unsigned long new_virt_end; + unsigned long ram_phys_addr; + unsigned long ram_start = 0; + int i; + + slot = &d->state.ram->mem_slot; + start = slot->mem_start; + end = slot->mem_end; + + printf("%s: slot %d start: 0x%lx end: 0x%lx\n", __FUNCTION__, slot_id, start, end); + + PANIC_ON(slot_id >= NUM_MEMSLOTS); + PANIC_ON(d->state.mem_slots[slot_id].active); + PANIC_ON(slot_id == 0); + + for (i = 0; i < d->state.num_ranges; ++i) { + if (address_in_range(start, end, &d->state.address_ranges[i])) { + ram_phys_addr = d->state.address_ranges[i].phys_start; + ram_start = d->state.address_ranges[i].virt_start; + break; + } + } + + if (!ram_start) { + printf("%s: invalid address range\n", __FUNCTION__); + exit(-1); + } + + start_offset = start - ram_phys_addr; + end_offset = end - ram_phys_addr; + + new_virt_start = ram_start + start_offset; + new_virt_end = ram_start + end_offset; + + qxl_check_memslot_range(d, new_virt_start, new_virt_end); + + device_slot = &d->state.mem_slots[slot_id]; + device_slot->active = TRUE; + device_slot->address_delta = ram_start + start - ram_phys_addr; + device_slot->virt_start = new_virt_start; + device_slot->virt_end = new_virt_end; + + qxl_dev_slot.slot_id = slot_id; + qxl_dev_slot.addr_delta = device_slot->address_delta; + qxl_dev_slot.virt_start = device_slot->virt_start; + qxl_dev_slot.virt_end = device_slot->virt_end; + qxl_dev_slot.generation = d->state.rom->slot_generation = device_slot->generation++; + + d->worker->add_memslot(d->worker, &qxl_dev_slot); +} + +static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id) +{ + MemSlot *device_slot; + + printf("%s: slot %d\n", __FUNCTION__, slot_id); + + PANIC_ON(slot_id >= NUM_MEMSLOTS); + PANIC_ON(slot_id == 0); + device_slot = &d->state.mem_slots[slot_id]; + PANIC_ON(!device_slot->active); + device_slot->active = FALSE; + + d->worker->del_memslot(d->worker, slot_id); +} + +static inline int is_any_none_host_slot_active(PCIQXLDevice *d) +{ + int i; + + for (i = 1; i < NUM_MEMSLOTS; ++i) { + if (d->state.mem_slots[i].active) { + return TRUE; + } + } + return FALSE; +} + static void ioport_write(void *opaque, uint32_t addr, uint32_t val) { PCIQXLDevice *d = (PCIQXLDevice *)opaque; @@ -912,7 +1122,9 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) #ifdef DEBUG_QXL printf("%s: addr 0x%x val 0x%x\n", __FUNCTION__, addr, val); #endif - if (d->state.mode != QXL_MODE_NATIVE && io_port != QXL_IO_RESET && io_port != QXL_IO_SET_MODE) { + if (d->state.mode != QXL_MODE_NATIVE && io_port != QXL_IO_RESET && + io_port != QXL_IO_SET_MODE && io_port != QXL_IO_MEMSLOT_ADD && + io_port != QXL_IO_MEMSLOT_DEL) { printf("%s: unexpected port 0x%x in vga mode\n", __FUNCTION__, io_port); return; } @@ -945,12 +1157,18 @@ static void ioport_write(void *opaque, uint32_t addr, uint32_t val) break; case QXL_IO_RESET: printf("%u: QXL_IO_RESET\n", d->id); - qxl_reset(d); + qxl_hard_reset(d); break; case QXL_IO_SET_MODE: printf("%u: QXL_IO_SET_MODE\n", d->id); qxl_set_mode(d, val); break; + case QXL_IO_MEMSLOT_ADD: + qxl_add_memslot(d, val); + break; + case QXL_IO_MEMSLOT_DEL: + qxl_del_memslot(d, val); + break; default: printf("%s: unexpected addr 0x%x val 0x%x\n", __FUNCTION__, addr, val); } @@ -997,8 +1215,14 @@ static void ram_map(PCIDevice *d, int region_num, ASSERT((addr & ~TARGET_PAGE_MASK) == 0); ASSERT(size == s->ram_size); ASSERT((size & ~TARGET_PAGE_MASK) == 0); + PANIC_ON(is_any_none_host_slot_active((PCIQXLDevice *)d)); s->ram_phys_addr = addr; cpu_register_physical_memory(addr, size, s->ram_offset | IO_MEM_RAM); + + s->address_ranges[0].virt_start = (unsigned long)s->ram_start; + s->address_ranges[0].virt_end = s->address_ranges[0].virt_start + size; + s->address_ranges[0].phys_start = addr; + s->address_ranges[0].phys_end = s->address_ranges[0].phys_start + size; } static void vram_map(PCIDevice *d, int region_num, @@ -1086,6 +1310,11 @@ static uint32_t init_qxl_rom(PCIQXLDevice *d, uint8_t *buf, uint32_t vram_size, rom->compression_level = QXL_DEFAULT_COMPRESSION_LEVEL; rom->log_level = 0; + rom->slot_gen_bits = MEMSLOT_GENERATION_BITS; + rom->slot_id_bits = MEMSLOT_SLOT_BITS; + rom->slots_start = 1; + rom->slots_end = NUM_MEMSLOTS - 1; + *max_fb = 0; modes->n_modes = sizeof(qxl_modes) / sizeof(QXLMode); @@ -1445,12 +1674,22 @@ static void init_pipe_signaling(PCIQXLDevice *d) fcntl(d->pipe_fd[0], F_SETOWN, getpid()); } +static void qxl_reset_device_address_ranges(PCIQXLDevice *d) +{ + memset(&d->state.address_ranges[0], 0, sizeof(QXLAddressRange)); +} + static void reset_handler(void *opaque) { PCIQXLDevice *d = (PCIQXLDevice *)opaque; - if (!QXL_SHARED_VGA_MODE && d->id > 0) { - qxl_reset(d); - } + + qxl_hard_reset(d); + qxl_reset_device_address_ranges(d); +} + +void qxl_get_init_info(QXLDevRef dev_ref, QXLDevInitInfo *info) +{ + _qxl_get_init_info((PCIQXLDevice *)dev_ref, info); } void qxl_get_info(QXLDevRef dev_ref, QXLDevInfo *info) @@ -1595,6 +1834,11 @@ static void interface_unregister_mode_change(QXLInterface *qxl, VDObjectRef noti unregister_mode_notifier(d, (QXLModeNotifier *)notifier); } +static void interface_get_init_info(QXLInterface *qxl, QXLDevInitInfo *info) +{ + _qxl_get_init_info(((Interface *)qxl)->d, info); +} + static void interface_get_info(QXLInterface *qxl, QXLDevInfo *info) { _qxl_get_info(((Interface *)qxl)->d, info); @@ -1680,6 +1924,7 @@ static void regitser_interface(PCIQXLDevice *d) interface->vd_interface.register_mode_change = interface_register_mode_change; interface->vd_interface.unregister_mode_change = interface_unregister_mode_change; + interface->vd_interface.get_init_info = interface_get_init_info; interface->vd_interface.get_info = interface_get_info; interface->vd_interface.get_command = interface_get_command; interface->vd_interface.req_cmd_notification = interface_req_cmd_notification; @@ -1891,8 +2136,9 @@ static void vdi_port_init(PCIBus *bus, uint8_t *ram, unsigned long ram_offset, qemu_add_vm_change_state_handler(vdi_port_vm_change_state_handler, d); } -void qxl_init(PCIBus *bus, uint8_t *vram, unsigned long vram_offset, - uint32_t vram_size, uint32_t in_ram_size) +void qxl_init(PCIBus *bus, uint8_t *vram, unsigned long vram_offset, + uint32_t vram_size, uint32_t in_ram_size, QXLAddressRange *address_ranges, + uint8_t num_ranges) { PCIQXLDevice *d; PCIConf *pci_conf; @@ -1900,9 +2146,10 @@ void qxl_init(PCIBus *bus, uint8_t *vram, unsigned long vram_offset, uint32_t max_fb; uint32_t qxl_ram_size = msb_mask(in_ram_size*2 - 1); uint32_t vdi_port_ram_size = msb_mask(sizeof(VDIPortRam) * 2 - 1); + int i; static int device_id = 0; - + if (device_id == 0) { vdi_port_init(bus, vram, vram_offset, vdi_port_ram_size); } @@ -1955,6 +2202,14 @@ void qxl_init(PCIBus *bus, uint8_t *vram, unsigned long vram_offset, d->state.vram_offset = vram_offset + rom_size + qxl_ram_size; d->state.vram_size = msb_mask(vram_size - (qxl_ram_size + rom_size)); + d->state.address_ranges = (QXLAddressRange *)malloc(sizeof(QXLAddressRange) * (num_ranges + 1)); + PANIC_ON(!d->state.address_ranges); + qxl_reset_device_address_ranges(d); + for (i = 0; i < num_ranges; ++i) { + d->state.address_ranges[i + 1] = address_ranges[i]; + } + d->state.num_ranges = num_ranges + 1; + printf("%s: rom(%p, 0x%x, 0x%x) ram(%p, 0x%x, 0x%x) vram(%p, 0x%lx, 0x%x)\n", __FUNCTION__, d->state.rom, @@ -1994,6 +2249,7 @@ void qxl_init(PCIBus *bus, uint8_t *vram, unsigned long vram_offset, qxl_vga.clients = d; main_thread = pthread_self(); qxl_reset_state(d); + qxl_init_memslots(d); init_pipe_signaling(d); #ifdef CONFIG_SPICE @@ -2002,6 +2258,7 @@ void qxl_init(PCIBus *bus, uint8_t *vram, unsigned long vram_offset, if (!d->worker) { creat_native_worker(d, device_id); } + qxl_create_host_memslot(d); if (QXL_SHARED_VGA_MODE || !d->id) { qxl_enter_vga_mode(d); d->worker->attach(d->worker); diff --git a/qemu/hw/qxl_dev.h b/qemu/hw/qxl_dev.h index def2bc99..d49978fe 100644 --- a/qemu/hw/qxl_dev.h +++ b/qemu/hw/qxl_dev.h @@ -21,7 +21,7 @@ #define REDHAT_PCI_VENDOR_ID 0x1b36 #define QXL_DEVICE_ID 0x0100 /* 0x100-0x11f reserved for spice */ -#define QXL_REVISION 0x01 +#define QXL_REVISION 0x02 #define QXL_ROM_MAGIC (*(UINT32*)"QXRO") #define QXL_RAM_MAGIC (*(UINT32*)"QXRA") @@ -44,6 +44,8 @@ enum { QXL_IO_RESET, QXL_IO_SET_MODE, QXL_IO_LOG, + QXL_IO_MEMSLOT_ADD, + QXL_IO_MEMSLOT_DEL, QXL_IO_RANGE_SIZE }; @@ -62,6 +64,12 @@ typedef struct ATTR_PACKED QXLRom { UINT32 draw_area_size; UINT32 ram_header_offset; UINT32 mm_clock; + UINT64 flags; + UINT8 slots_start; + UINT8 slots_end; + UINT8 slot_gen_bits; + UINT8 slot_id_bits; + UINT8 slot_generation; } QXLRom; typedef struct ATTR_PACKED QXLMode { @@ -97,6 +105,10 @@ typedef struct ATTR_PACKED QXLCommand { UINT32 ped; } QXLCommand; +typedef struct ATTR_PACKED QXLMemSlot { + UINT64 mem_start; + UINT64 mem_end; +} QXLMemSlot; RING_DECLARE(QXLCommandRing, QXLCommand, 32); RING_DECLARE(QXLCursorRing, QXLCommand, 32); @@ -117,6 +129,8 @@ typedef struct ATTR_PACKED QXLRam { QXLCursorRing cursor_ring; QXLReleaseRing release_ring; Rect update_area; + QXLMemSlot mem_slot; + UINT64 flags; } QXLRam; typedef union QXLReleaseInfo{ diff --git a/qemu/hw/qxl_interface.h b/qemu/hw/qxl_interface.h index 95cd31d0..6de2d7d4 100644 --- a/qemu/hw/qxl_interface.h +++ b/qemu/hw/qxl_interface.h @@ -21,17 +21,31 @@ typedef struct DrawArea{ } DrawArea; typedef struct QXLDevInfo { - long phys_delta; - unsigned long phys_start; - unsigned long phys_end; uint32_t x_res; uint32_t y_res; int use_hardware_cursor; uint32_t bits; DrawArea draw_area; uint32_t ram_size; + uint32_t num_memslots; + uint8_t mem_generation_bits; + uint8_t mem_slot_bits; } QXLDevInfo; +typedef struct QXLDevInitInfo { + uint32_t num_memslots; + uint8_t memslot_gen_bits; + uint8_t memslot_id_bits; +} QXLDevInitInfo; + +typedef struct QXLDevMemSlot { + uint32_t slot_id; + uint32_t generation; + unsigned long virt_start; + unsigned long virt_end; + uint64_t addr_delta; +} QXLDevMemSlot; + typedef struct QXLWorker QXLWorker; struct QXLWorker { void (*attach)(QXLWorker *worker); @@ -43,11 +57,15 @@ struct QXLWorker { void (*start)(QXLWorker *worker); void (*stop)(QXLWorker *worker); void (*update_area)(QXLWorker *worker); + void (*add_memslot)(QXLWorker *worker, QXLDevMemSlot *slot); + void (*del_memslot)(QXLWorker *worker, uint32_t slot_id); + void (*reset_memslots)(QXLWorker *worker); }; #endif typedef unsigned long QXLDevRef; +void qxl_get_init_info(QXLDevRef dev_ref, QXLDevInitInfo *info); void qxl_get_info(QXLDevRef dev_ref, QXLDevInfo *info); int qxl_get_command(QXLDevRef dev_ref, QXLCommand *cmd); void qxl_release_resource(QXLDevRef dev_ref, QXLReleaseInfo *release_info); diff --git a/qemu/hw/qxl_native_worker.c b/qemu/hw/qxl_native_worker.c index 91eefb1d..044ac3d7 100644 --- a/qemu/hw/qxl_native_worker.c +++ b/qemu/hw/qxl_native_worker.c @@ -15,13 +15,94 @@ #define qxl_printf(format, ...) \ printf("%s: " format "\n", __FUNCTION__, ## __VA_ARGS__ ) +#define ASSERT(x) if (!(x)) { \ + printf("%s: ASSERT %s failed\n", __FUNCTION__, #x); \ + exit(-1); \ +} + +typedef struct MemSlot { + int active; + int generation; + unsigned long virt_start_addr; + unsigned long virt_end_addr; + unsigned long address_delta; +} MemSlot; + typedef struct QxlDispatcher { QXLWorker base; int id; QXLDevRef dev_ref; + uint32_t nmem_slots; + MemSlot *mem_slots; + uint8_t generation_bits; + uint8_t mem_slot_bits; QXLDevInfo dev_info; } QxlDispatcher; +static inline int get_memslot_id(QXLWorker *worker, unsigned long addr) +{ + QxlDispatcher *dispatcher = (QxlDispatcher *)worker; + + return addr >> (64 - dispatcher->mem_slot_bits); +} + +static inline int get_generation(QXLWorker *worker, unsigned long addr) +{ + QxlDispatcher *dispatcher = (QxlDispatcher *)worker; + + return (addr >> (64 - (dispatcher->mem_slot_bits + dispatcher->generation_bits))) & + ~((unsigned long)-1 << dispatcher->generation_bits); +} + +static inline unsigned long __get_clean_virt(QXLWorker *worker, unsigned long addr) +{ + QxlDispatcher *dispatcher = (QxlDispatcher *)worker; + + return addr & (((unsigned long)(-1)) >> (dispatcher->mem_slot_bits + dispatcher->generation_bits)); +} + +static inline void validate_virt(QXLWorker *worker, unsigned long virt, int slot_id, uint32_t add_size) +{ + MemSlot *slot; + QxlDispatcher *dispatcher = (QxlDispatcher *)worker; + + slot = &dispatcher->mem_slots[slot_id]; + if (virt < slot->virt_start_addr || (virt + add_size) > slot->virt_end_addr) { + qxl_error("virtual address out of range 0x%lx 0x%lx", virt, slot->address_delta); + } +} + +static inline unsigned long get_virt(QXLWorker *worker, unsigned long addr, uint32_t add_size) +{ + uint32_t slot_id; + int generation; + unsigned long h_virt; + MemSlot *slot; + QxlDispatcher *dispatcher = (QxlDispatcher *)worker; + + slot_id = get_memslot_id(worker, addr); + if (slot_id > dispatcher->nmem_slots) { + qxl_error("slot_id too big"); + } + + slot = &dispatcher->mem_slots[slot_id]; + if (!slot->active) { + qxl_error("mem_slot is not avaible %d 0x%lx", slot_id, addr); + } + + generation = get_generation(worker, addr); + if (generation != slot->generation) { + qxl_error("address generation is not valid"); + } + + h_virt = __get_clean_virt(worker, addr); + h_virt += slot->address_delta; + + validate_virt(worker, h_virt, slot_id, add_size); + + return h_virt; +} + static void native_qxl_worker_wakeup(QXLWorker *worker) { QxlDispatcher *dispatcher = (QxlDispatcher *)worker; @@ -33,18 +114,18 @@ static void native_qxl_worker_wakeup(QXLWorker *worker) if (qxl_get_command(dispatcher->dev_ref, &cmd)) { switch (cmd.type) { case QXL_CMD_DRAW: { - QXLDrawable *draw_cmd = (QXLDrawable *)(cmd.data + dispatcher->dev_info.phys_delta); + QXLDrawable *draw_cmd = (QXLDrawable *)get_virt(worker, cmd.data, sizeof(QXLDrawable)); qxl_release_resource(dispatcher->dev_ref, &draw_cmd->release_info); break; } case QXL_CMD_UPDATE: { - QXLUpdateCmd *update_cmd = (QXLUpdateCmd *)(cmd.data + dispatcher->dev_info.phys_delta); + QXLUpdateCmd *update_cmd = (QXLUpdateCmd *)get_virt(worker, cmd.data, sizeof(QXLUpdateCmd)); qxl_notify_update(dispatcher->dev_ref, update_cmd->update_id); qxl_release_resource(dispatcher->dev_ref, &update_cmd->release_info); break; } case QXL_CMD_MESSAGE: { - QXLMessage *message = (QXLMessage *)(cmd.data + dispatcher->dev_info.phys_delta); + QXLMessage *message = (QXLMessage *)get_virt(worker, cmd.data, sizeof(QXLMessage)); qxl_printf("MESSAGE: %s", message->data); qxl_release_resource(dispatcher->dev_ref, &message->release_info); break; @@ -62,7 +143,7 @@ static void native_qxl_worker_wakeup(QXLWorker *worker) if (qxl_get_cursor_command(dispatcher->dev_ref, &cmd)) { switch (cmd.type) { case QXL_CMD_CURSOR: { - QXLCursorCmd *cursor_cmd = (QXLCursorCmd *)(cmd.data + dispatcher->dev_info.phys_delta); + QXLCursorCmd *cursor_cmd = (QXLCursorCmd *)get_virt(worker, cmd.data, sizeof(QXLCursorCmd)); qxl_release_resource(dispatcher->dev_ref, &cursor_cmd->release_info); break; } @@ -84,12 +165,21 @@ static void native_qxl_worker_attach(QXLWorker *worker) qxl_printf(""); qxl_get_info(dispatcher->dev_ref, &dispatcher->dev_info); + native_qxl_worker_wakeup(worker); } +static void native_qxl_worerk_reset_memslots(QXLWorker *worker) +{ + QxlDispatcher *dispatcher = (QxlDispatcher *)worker; + + memset(dispatcher->mem_slots, 0, sizeof(MemSlot) * dispatcher->nmem_slots); +} + static void native_qxl_worker_detach(QXLWorker *worker) { qxl_printf(""); + native_qxl_worker_wakeup(worker); } @@ -99,6 +189,34 @@ static void native_qxl_worker_update_area(QXLWorker *worker) native_qxl_worker_wakeup(worker); } +static void native_qxl_worker_add_memslot(QXLWorker *worker, QXLDevMemSlot *dev_slot) +{ + QxlDispatcher *dispatcher = (QxlDispatcher *)worker; + + qxl_printf(""); + + ASSERT(dispatcher->nmem_slots > dev_slot->slot_id); + ASSERT(!dispatcher->mem_slots[dev_slot->slot_id].active); + + dispatcher->mem_slots[dev_slot->slot_id].active = 1; + dispatcher->mem_slots[dev_slot->slot_id].address_delta = dev_slot->addr_delta; + dispatcher->mem_slots[dev_slot->slot_id].virt_start_addr = dev_slot->virt_start; + dispatcher->mem_slots[dev_slot->slot_id].virt_end_addr = dev_slot->virt_end; + dispatcher->mem_slots[dev_slot->slot_id].generation = dev_slot->generation; +} + +static void native_qxl_worker_del_memslot(QXLWorker *worker, uint32_t slot_id) +{ + QxlDispatcher *dispatcher = (QxlDispatcher *)worker; + + qxl_printf(""); + + ASSERT(dispatcher->nmem_slots > slot_id); + ASSERT(dispatcher->mem_slots[slot_id].active); + + dispatcher->mem_slots[slot_id].active = 0; +} + static void native_qxl_worker_oom(QXLWorker *worker) { qxl_printf(""); @@ -128,6 +246,7 @@ static void native_qxl_worker_load(QXLWorker *worker) QXLWorker *qxl_interface_create_worker(QXLDevRef dev_ref, int device_id) { QxlDispatcher *dispatcher; + QXLDevInitInfo init; if (!(dispatcher = malloc(sizeof(QxlDispatcher)))) { qxl_error("malloc failed"); @@ -145,6 +264,18 @@ QXLWorker *qxl_interface_create_worker(QXLDevRef dev_ref, int device_id) dispatcher->base.start = native_qxl_worker_start; dispatcher->base.stop = native_qxl_worker_stop; dispatcher->base.update_area = native_qxl_worker_update_area; + dispatcher->base.add_memslot = native_qxl_worker_add_memslot; + dispatcher->base.del_memslot = native_qxl_worker_del_memslot; + dispatcher->base.reset_memslots = native_qxl_worerk_reset_memslots; + + qxl_get_init_info(dispatcher->dev_ref, &init); + + dispatcher->mem_slots = (MemSlot *)malloc(sizeof(MemSlot) * init.num_memslots); + ASSERT(dispatcher->mem_slots); + memset(dispatcher->mem_slots, 0, sizeof(MemSlot) * init.num_memslots); + dispatcher->nmem_slots = init.num_memslots; + dispatcher->mem_slot_bits = init.memslot_id_bits; + dispatcher->generation_bits = init.memslot_gen_bits; return &dispatcher->base; } -- cgit v1.2.3