summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIzik Eidus <ieidus@redhat.com>2009-11-21 22:43:28 +0200
committerYaniv Kamay <ykamay@redhat.com>2009-11-23 20:57:04 +0200
commit7fe765d123c9ade3613f6128ae86a3be7a602d60 (patch)
treea396b27dd8a352023e53349799beea35d2685375
parentcef9698cb045f0e447736f257d4d2ff88c7fd8e0 (diff)
vdesktop: add memslot support
Signed-off-by: Izik Eidus <ieidus@redhat.com>
-rwxr-xr-xqemu/configure2
-rw-r--r--qemu/hw/pc.c19
-rw-r--r--qemu/hw/pc.h11
-rw-r--r--qemu/hw/qxl.c285
-rw-r--r--qemu/hw/qxl_dev.h16
-rw-r--r--qemu/hw/qxl_interface.h24
-rw-r--r--qemu/hw/qxl_native_worker.c139
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;
}