aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--backends/rng-random.c18
-rw-r--r--block/iscsi.c1
-rwxr-xr-xconfigure2
-rw-r--r--cpus.c16
-rw-r--r--docs/atomics.txt4
-rw-r--r--exec.c64
-rw-r--r--hw/arm/virt.c4
-rw-r--r--hw/core/machine.c31
-rw-r--r--hw/core/nmi.c24
-rw-r--r--hw/display/vga.c50
-rw-r--r--hw/display/vga_int.h1
-rw-r--r--hw/display/virtio-gpu-3d.c5
-rw-r--r--hw/display/virtio-gpu.c28
-rw-r--r--hw/display/virtio-vga.c8
-rw-r--r--hw/i386/kvmvapic.c2
-rw-r--r--hw/i386/pc.c20
-rw-r--r--hw/i386/pc_piix.c13
-rw-r--r--hw/intc/ioapic.c33
-rw-r--r--hw/lm32/milkymist-hw.h4
-rw-r--r--hw/lm32/milkymist.c4
-rw-r--r--hw/net/opencores_eth.c44
-rw-r--r--hw/nvram/fw_cfg.c6
-rw-r--r--hw/ppc/spapr.c4
-rw-r--r--hw/s390x/s390-virtio-ccw.c1
-rw-r--r--hw/scsi/esp.c17
-rw-r--r--hw/sparc/sun4m.c2
-rw-r--r--hw/usb/Makefile.objs4
-rw-r--r--hw/usb/hcd-ohci.c6
-rw-r--r--hw/usb/xen-usb.c1080
-rw-r--r--hw/watchdog/watchdog.c2
-rw-r--r--hw/xen/xen_backend.c63
-rw-r--r--hw/xen/xen_devconfig.c52
-rw-r--r--hw/xenpv/xen_machine_pv.c43
-rw-r--r--include/exec/cpu-common.h4
-rw-r--r--include/exec/memory.h1
-rw-r--r--include/exec/ram_addr.h2
-rw-r--r--include/hw/boards.h12
-rw-r--r--include/hw/i386/ioapic_internal.h5
-rw-r--r--include/hw/i386/pc.h9
-rw-r--r--include/hw/mem/pc-dimm.h4
-rw-r--r--include/hw/nmi.h1
-rw-r--r--include/hw/virtio/virtio-gpu.h6
-rw-r--r--include/hw/virtio/virtio-rng.h2
-rw-r--r--include/hw/xen/xen_backend.h6
-rw-r--r--include/hw/xen/xen_common.h2
-rw-r--r--include/qemu/osdep.h13
-rw-r--r--include/sysemu/rng-random.h4
-rw-r--r--include/sysemu/sysemu.h12
-rw-r--r--include/ui/console.h71
-rw-r--r--include/ui/qemu-spice.h13
-rw-r--r--memory.c46
-rw-r--r--migration/ram.c2
-rw-r--r--migration/savevm.c4
-rw-r--r--qemu-img.c5
-rw-r--r--qemu-io.c5
-rw-r--r--qemu-nbd.c5
-rw-r--r--scripts/cocci-macro-file.h6
-rw-r--r--scripts/signrom.py28
-rw-r--r--target-i386/translate.c5
-rw-r--r--translate-all.c3
-rw-r--r--util/oslib-posix.c13
-rw-r--r--vl.c294
63 files changed, 1716 insertions, 524 deletions
diff --git a/Makefile b/Makefile
index 1d076a9d85..a5d7e62626 100644
--- a/Makefile
+++ b/Makefile
@@ -356,6 +356,7 @@ clean:
if test -d $$d; then $(MAKE) -C $$d $@ || exit 1; fi; \
rm -f $$d/qemu-options.def; \
done
+ rm -f $(SUBDIR_DEVICES_MAK) config-all-devices.mak
VERSION ?= $(shell cat VERSION)
diff --git a/backends/rng-random.c b/backends/rng-random.c
index 2e44e25190..e2a49b0571 100644
--- a/backends/rng-random.c
+++ b/backends/rng-random.c
@@ -17,7 +17,7 @@
#include "qapi/qmp/qerror.h"
#include "qemu/main-loop.h"
-struct RndRandom
+struct RngRandom
{
RngBackend parent;
@@ -34,7 +34,7 @@ struct RndRandom
static void entropy_available(void *opaque)
{
- RndRandom *s = RNG_RANDOM(opaque);
+ RngRandom *s = RNG_RANDOM(opaque);
while (!QSIMPLEQ_EMPTY(&s->parent.requests)) {
RngRequest *req = QSIMPLEQ_FIRST(&s->parent.requests);
@@ -57,7 +57,7 @@ static void entropy_available(void *opaque)
static void rng_random_request_entropy(RngBackend *b, RngRequest *req)
{
- RndRandom *s = RNG_RANDOM(b);
+ RngRandom *s = RNG_RANDOM(b);
if (QSIMPLEQ_EMPTY(&s->parent.requests)) {
/* If there are no pending requests yet, we need to
@@ -68,7 +68,7 @@ static void rng_random_request_entropy(RngBackend *b, RngRequest *req)
static void rng_random_opened(RngBackend *b, Error **errp)
{
- RndRandom *s = RNG_RANDOM(b);
+ RngRandom *s = RNG_RANDOM(b);
if (s->filename == NULL) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
@@ -83,7 +83,7 @@ static void rng_random_opened(RngBackend *b, Error **errp)
static char *rng_random_get_filename(Object *obj, Error **errp)
{
- RndRandom *s = RNG_RANDOM(obj);
+ RngRandom *s = RNG_RANDOM(obj);
return g_strdup(s->filename);
}
@@ -92,7 +92,7 @@ static void rng_random_set_filename(Object *obj, const char *filename,
Error **errp)
{
RngBackend *b = RNG_BACKEND(obj);
- RndRandom *s = RNG_RANDOM(obj);
+ RngRandom *s = RNG_RANDOM(obj);
if (b->opened) {
error_setg(errp, QERR_PERMISSION_DENIED);
@@ -105,7 +105,7 @@ static void rng_random_set_filename(Object *obj, const char *filename,
static void rng_random_init(Object *obj)
{
- RndRandom *s = RNG_RANDOM(obj);
+ RngRandom *s = RNG_RANDOM(obj);
object_property_add_str(obj, "filename",
rng_random_get_filename,
@@ -118,7 +118,7 @@ static void rng_random_init(Object *obj)
static void rng_random_finalize(Object *obj)
{
- RndRandom *s = RNG_RANDOM(obj);
+ RngRandom *s = RNG_RANDOM(obj);
if (s->fd != -1) {
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
@@ -139,7 +139,7 @@ static void rng_random_class_init(ObjectClass *klass, void *data)
static const TypeInfo rng_random_info = {
.name = TYPE_RNG_RANDOM,
.parent = TYPE_RNG_BACKEND,
- .instance_size = sizeof(RndRandom),
+ .instance_size = sizeof(RngRandom),
.class_init = rng_random_class_init,
.instance_init = rng_random_init,
.instance_finalize = rng_random_finalize,
diff --git a/block/iscsi.c b/block/iscsi.c
index 10f3906bcc..2ca8e72967 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -761,6 +761,7 @@ iscsi_aio_ioctl_cb(struct iscsi_context *iscsi, int status,
acb->ioh->driver_status = 0;
acb->ioh->host_status = 0;
acb->ioh->resid = 0;
+ acb->ioh->status = status;
#define SG_ERR_DRIVER_SENSE 0x08
diff --git a/configure b/configure
index 293639cf6d..b5aab7257b 100755
--- a/configure
+++ b/configure
@@ -2985,7 +2985,7 @@ int main(void) {
}
EOF
-if ! compile_prog "-Werror $CFLAGS" "$LIBS" ; then
+if ! compile_prog "$CFLAGS" "$LIBS" ; then
error_exit "sizeof(size_t) doesn't match GLIB_SIZEOF_SIZE_T."\
"You probably need to set PKG_CONFIG_LIBDIR"\
"to point to the right pkg-config files for your"\
diff --git a/cpus.c b/cpus.c
index eb34b4fe76..e75895a458 100644
--- a/cpus.c
+++ b/cpus.c
@@ -780,7 +780,7 @@ static void sigbus_reraise(void)
raise(SIGBUS);
sigemptyset(&set);
sigaddset(&set, SIGBUS);
- sigprocmask(SIG_UNBLOCK, &set, NULL);
+ pthread_sigmask(SIG_UNBLOCK, &set, NULL);
}
perror("Failed to re-raise SIGBUS!\n");
abort();
@@ -1693,21 +1693,7 @@ exit:
void qmp_inject_nmi(Error **errp)
{
-#if defined(TARGET_I386)
- CPUState *cs;
-
- CPU_FOREACH(cs) {
- X86CPU *cpu = X86_CPU(cs);
-
- if (!cpu->apic_state) {
- cpu_interrupt(cs, CPU_INTERRUPT_NMI);
- } else {
- apic_deliver_nmi(cpu->apic_state);
- }
- }
-#else
nmi_monitor_handle(monitor_get_cpu_index(), errp);
-#endif
}
void dump_drift_info(FILE *f, fprintf_function cpu_fprintf)
diff --git a/docs/atomics.txt b/docs/atomics.txt
index ef285e3c2a..bba771ecd6 100644
--- a/docs/atomics.txt
+++ b/docs/atomics.txt
@@ -62,7 +62,7 @@ operations:
typeof(*ptr) atomic_fetch_sub(ptr, val)
typeof(*ptr) atomic_fetch_and(ptr, val)
typeof(*ptr) atomic_fetch_or(ptr, val)
- typeof(*ptr) atomic_xchg(ptr, val
+ typeof(*ptr) atomic_xchg(ptr, val)
typeof(*ptr) atomic_cmpxchg(ptr, old, new)
all of which return the old value of *ptr. These operations are
@@ -328,7 +328,7 @@ and memory barriers, and the equivalents in QEMU:
- atomic_read and atomic_set in Linux give no guarantee at all;
atomic_read and atomic_set in QEMU include a compiler barrier
- (similar to the ACCESS_ONCE macro in Linux).
+ (similar to the READ_ONCE/WRITE_ONCE macros in Linux).
- most atomic read-modify-write operations in Linux return void;
in QEMU, all of them return the old value of the variable.
diff --git a/exec.c b/exec.c
index 2e363f06a6..a3a93aeed3 100644
--- a/exec.c
+++ b/exec.c
@@ -1046,8 +1046,7 @@ hwaddr memory_region_section_get_iotlb(CPUState *cpu,
if (memory_region_is_ram(section->mr)) {
/* Normal RAM. */
- iotlb = (memory_region_get_ram_addr(section->mr) & TARGET_PAGE_MASK)
- + xlat;
+ iotlb = memory_region_get_ram_addr(section->mr) + xlat;
if (!section->readonly) {
iotlb |= PHYS_SECTION_NOTDIRTY;
} else {
@@ -1299,7 +1298,7 @@ static void *file_ram_alloc(RAMBlock *block,
}
page_size = qemu_fd_getpagesize(fd);
- block->mr->align = page_size;
+ block->mr->align = MAX(page_size, QEMU_VMALLOC_ALIGN);
if (memory < page_size) {
error_setg(errp, "memory size 0x" RAM_ADDR_FMT " must be equal to "
@@ -1320,7 +1319,8 @@ static void *file_ram_alloc(RAMBlock *block,
perror("ftruncate");
}
- area = qemu_ram_mmap(fd, memory, page_size, block->flags & RAM_SHARED);
+ area = qemu_ram_mmap(fd, memory, block->mr->align,
+ block->flags & RAM_SHARED);
if (area == MAP_FAILED) {
error_setg_errno(errp, errno,
"unable to map backing store for guest RAM");
@@ -1410,34 +1410,16 @@ static void qemu_ram_setup_dump(void *addr, ram_addr_t size)
}
}
-/* Called within an RCU critical section, or while the ramlist lock
- * is held.
- */
-static RAMBlock *find_ram_block(ram_addr_t addr)
-{
- RAMBlock *block;
-
- QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
- if (block->offset == addr) {
- return block;
- }
- }
-
- return NULL;
-}
-
const char *qemu_ram_get_idstr(RAMBlock *rb)
{
return rb->idstr;
}
/* Called with iothread lock held. */
-void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev)
+void qemu_ram_set_idstr(RAMBlock *new_block, const char *name, DeviceState *dev)
{
- RAMBlock *new_block, *block;
+ RAMBlock *block;
- rcu_read_lock();
- new_block = find_ram_block(addr);
assert(new_block);
assert(!new_block->idstr[0]);
@@ -1450,8 +1432,10 @@ void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev)
}
pstrcat(new_block->idstr, sizeof(new_block->idstr), name);
+ rcu_read_lock();
QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
- if (block != new_block && !strcmp(block->idstr, new_block->idstr)) {
+ if (block != new_block &&
+ !strcmp(block->idstr, new_block->idstr)) {
fprintf(stderr, "RAMBlock \"%s\" already registered, abort!\n",
new_block->idstr);
abort();
@@ -1461,21 +1445,15 @@ void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev)
}
/* Called with iothread lock held. */
-void qemu_ram_unset_idstr(ram_addr_t addr)
+void qemu_ram_unset_idstr(RAMBlock *block)
{
- RAMBlock *block;
-
/* FIXME: arch_init.c assumes that this is not called throughout
* migration. Ignore the problem since hot-unplug during migration
* does not work anyway.
*/
-
- rcu_read_lock();
- block = find_ram_block(addr);
if (block) {
memset(block->idstr, 0, sizeof(block->idstr));
}
- rcu_read_unlock();
}
static int memory_try_enable_merging(void *addr, size_t len)
@@ -1495,10 +1473,8 @@ static int memory_try_enable_merging(void *addr, size_t len)
* resize callback to update device state and/or add assertions to detect
* misuse, if necessary.
*/
-int qemu_ram_resize(ram_addr_t base, ram_addr_t newsize, Error **errp)
+int qemu_ram_resize(RAMBlock *block, ram_addr_t newsize, Error **errp)
{
- RAMBlock *block = find_ram_block(base);
-
assert(block);
newsize = HOST_PAGE_ALIGN(newsize);
@@ -3102,9 +3078,7 @@ static inline uint32_t address_space_ldl_internal(AddressSpace *as, hwaddr addr,
} else {
/* RAM case */
ptr = qemu_get_ram_ptr(mr->ram_block,
- (memory_region_get_ram_addr(mr)
- & TARGET_PAGE_MASK)
- + addr1);
+ memory_region_get_ram_addr(mr) + addr1);
switch (endian) {
case DEVICE_LITTLE_ENDIAN:
val = ldl_le_p(ptr);
@@ -3198,9 +3172,7 @@ static inline uint64_t address_space_ldq_internal(AddressSpace *as, hwaddr addr,
} else {
/* RAM case */
ptr = qemu_get_ram_ptr(mr->ram_block,
- (memory_region_get_ram_addr(mr)
- & TARGET_PAGE_MASK)
- + addr1);
+ memory_region_get_ram_addr(mr) + addr1);
switch (endian) {
case DEVICE_LITTLE_ENDIAN:
val = ldq_le_p(ptr);
@@ -3314,9 +3286,7 @@ static inline uint32_t address_space_lduw_internal(AddressSpace *as,
} else {
/* RAM case */
ptr = qemu_get_ram_ptr(mr->ram_block,
- (memory_region_get_ram_addr(mr)
- & TARGET_PAGE_MASK)
- + addr1);
+ memory_region_get_ram_addr(mr) + addr1);
switch (endian) {
case DEVICE_LITTLE_ENDIAN:
val = lduw_le_p(ptr);
@@ -3398,7 +3368,7 @@ void address_space_stl_notdirty(AddressSpace *as, hwaddr addr, uint32_t val,
r = memory_region_dispatch_write(mr, addr1, val, 4, attrs);
} else {
- addr1 += memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK;
+ addr1 += memory_region_get_ram_addr(mr);
ptr = qemu_get_ram_ptr(mr->ram_block, addr1);
stl_p(ptr, val);
@@ -3453,7 +3423,7 @@ static inline void address_space_stl_internal(AddressSpace *as,
r = memory_region_dispatch_write(mr, addr1, val, 4, attrs);
} else {
/* RAM case */
- addr1 += memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK;
+ addr1 += memory_region_get_ram_addr(mr);
ptr = qemu_get_ram_ptr(mr->ram_block, addr1);
switch (endian) {
case DEVICE_LITTLE_ENDIAN:
@@ -3563,7 +3533,7 @@ static inline void address_space_stw_internal(AddressSpace *as,
r = memory_region_dispatch_write(mr, addr1, val, 2, attrs);
} else {
/* RAM case */
- addr1 += memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK;
+ addr1 += memory_region_get_ram_addr(mr);
ptr = qemu_get_ram_ptr(mr->ram_block, addr1);
switch (endian) {
case DEVICE_LITTLE_ENDIAN:
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index fe6b11d24e..e77ed88afb 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -1418,13 +1418,9 @@ static void virt_2_6_instance_init(Object *obj)
static void virt_2_6_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
- static GlobalProperty compat_props[] = {
- { /* end of list */ }
- };
mc->desc = "QEMU 2.6 ARM Virtual Machine";
mc->alias = "virt";
- mc->compat_props = compat_props;
}
static const TypeInfo machvirt_info = {
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 6dbbc85b97..ccdd5fa3e7 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -257,6 +257,20 @@ static void machine_set_usb(Object *obj, bool value, Error **errp)
ms->usb_disabled = !value;
}
+static bool machine_get_graphics(Object *obj, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+
+ return ms->enable_graphics;
+}
+
+static void machine_set_graphics(Object *obj, bool value, Error **errp)
+{
+ MachineState *ms = MACHINE(obj);
+
+ ms->enable_graphics = value;
+}
+
static bool machine_get_igd_gfx_passthru(Object *obj, Error **errp)
{
MachineState *ms = MACHINE(obj);
@@ -382,6 +396,7 @@ static void machine_initfn(Object *obj)
ms->kvm_shadow_mem = -1;
ms->dump_guest_core = true;
ms->mem_merge = true;
+ ms->enable_graphics = true;
object_property_add_str(obj, "accel",
machine_get_accel, machine_set_accel, NULL);
@@ -460,6 +475,12 @@ static void machine_initfn(Object *obj)
object_property_set_description(obj, "usb",
"Set on/off to enable/disable usb",
NULL);
+ object_property_add_bool(obj, "graphics",
+ machine_get_graphics,
+ machine_set_graphics, NULL);
+ object_property_set_description(obj, "graphics",
+ "Set on/off to enable/disable graphics emulation",
+ NULL);
object_property_add_bool(obj, "igd-passthru",
machine_get_igd_gfx_passthru,
machine_set_igd_gfx_passthru, NULL);
@@ -550,6 +571,15 @@ bool machine_mem_merge(MachineState *machine)
return machine->mem_merge;
}
+static void machine_class_finalize(ObjectClass *klass, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(klass);
+
+ if (mc->compat_props) {
+ g_array_free(mc->compat_props, true);
+ }
+}
+
static const TypeInfo machine_info = {
.name = TYPE_MACHINE,
.parent = TYPE_OBJECT,
@@ -557,6 +587,7 @@ static const TypeInfo machine_info = {
.class_size = sizeof(MachineClass),
.class_init = machine_class_init,
.class_base_init = machine_class_base_init,
+ .class_finalize = machine_class_finalize,
.instance_size = sizeof(MachineState),
.instance_init = machine_initfn,
.instance_finalize = machine_finalize,
diff --git a/hw/core/nmi.c b/hw/core/nmi.c
index f616a79312..bfd0896daf 100644
--- a/hw/core/nmi.c
+++ b/hw/core/nmi.c
@@ -20,16 +20,11 @@
*/
#include "qemu/osdep.h"
-#include "qom/cpu.h"
#include "hw/nmi.h"
#include "qapi/error.h"
#include "qapi/qmp/qerror.h"
#include "monitor/monitor.h"
-#if defined(TARGET_I386)
-#include "cpu.h"
-#endif
-
struct do_nmi_s {
int cpu_index;
Error *err;
@@ -78,25 +73,6 @@ void nmi_monitor_handle(int cpu_index, Error **errp)
}
}
-void inject_nmi(void)
-{
-#if defined(TARGET_I386)
- CPUState *cs;
-
- CPU_FOREACH(cs) {
- X86CPU *cpu = X86_CPU(cs);
-
- if (!cpu->apic_state) {
- cpu_interrupt(cs, CPU_INTERRUPT_NMI);
- } else {
- apic_deliver_nmi(cpu->apic_state);
- }
- }
-#else
- nmi_monitor_handle(0, NULL);
-#endif
-}
-
static const TypeInfo nmi_info = {
.name = TYPE_NMI,
.parent = TYPE_INTERFACE,
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 4a55ec6dbb..9ebc54f22b 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -149,6 +149,11 @@ static inline bool vbe_enabled(VGACommonState *s)
return s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED;
}
+static inline uint8_t sr(VGACommonState *s, int idx)
+{
+ return vbe_enabled(s) ? s->sr_vbe[idx] : s->sr[idx];
+}
+
static void vga_update_memory_access(VGACommonState *s)
{
hwaddr base, offset, size;
@@ -163,8 +168,8 @@ static void vga_update_memory_access(VGACommonState *s)
s->has_chain4_alias = false;
s->plane_updated = 0xf;
}
- if ((s->sr[VGA_SEQ_PLANE_WRITE] & VGA_SR02_ALL_PLANES) ==
- VGA_SR02_ALL_PLANES && s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
+ if ((sr(s, VGA_SEQ_PLANE_WRITE) & VGA_SR02_ALL_PLANES) ==
+ VGA_SR02_ALL_PLANES && sr(s, VGA_SEQ_MEMORY_MODE) & VGA_SR04_CHN_4M) {
offset = 0;
switch ((s->gr[VGA_GFX_MISC] >> 2) & 3) {
case 0:
@@ -234,7 +239,7 @@ static void vga_precise_update_retrace_info(VGACommonState *s)
((s->cr[VGA_CRTC_OVERFLOW] >> 6) & 2)) << 8);
vretr_end_line = s->cr[VGA_CRTC_V_SYNC_END] & 0xf;
- clocking_mode = (s->sr[VGA_SEQ_CLOCK_MODE] >> 3) & 1;
+ clocking_mode = (sr(s, VGA_SEQ_CLOCK_MODE) >> 3) & 1;
clock_sel = (s->msr >> 2) & 3;
dots = (s->msr & 1) ? 8 : 9;
@@ -486,7 +491,6 @@ void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
#endif
s->sr[s->sr_index] = val & sr_mask[s->sr_index];
- vbe_update_vgaregs(s);
if (s->sr_index == VGA_SEQ_CLOCK_MODE) {
s->update_retrace_info(s);
}
@@ -680,13 +684,13 @@ static void vbe_update_vgaregs(VGACommonState *s)
if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
shift_control = 0;
- s->sr[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
+ s->sr_vbe[VGA_SEQ_CLOCK_MODE] &= ~8; /* no double line */
} else {
shift_control = 2;
/* set chain 4 mode */
- s->sr[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
+ s->sr_vbe[VGA_SEQ_MEMORY_MODE] |= VGA_SR04_CHN_4M;
/* activate all planes */
- s->sr[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
+ s->sr_vbe[VGA_SEQ_PLANE_WRITE] |= VGA_SR02_ALL_PLANES;
}
s->gr[VGA_GFX_MODE] = (s->gr[VGA_GFX_MODE] & ~0x60) |
(shift_control << 5);
@@ -836,7 +840,7 @@ uint32_t vga_mem_readb(VGACommonState *s, hwaddr addr)
break;
}
- if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
+ if (sr(s, VGA_SEQ_MEMORY_MODE) & VGA_SR04_CHN_4M) {
/* chain 4 mode : simplest access */
assert(addr < s->vram_size);
ret = s->vram_ptr[addr];
@@ -904,11 +908,11 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
break;
}
- if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {
+ if (sr(s, VGA_SEQ_MEMORY_MODE) & VGA_SR04_CHN_4M) {
/* chain 4 mode : simplest access */
plane = addr & 3;
mask = (1 << plane);
- if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
+ if (sr(s, VGA_SEQ_PLANE_WRITE) & mask) {
assert(addr < s->vram_size);
s->vram_ptr[addr] = val;
#ifdef DEBUG_VGA_MEM
@@ -921,7 +925,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
/* odd/even mode (aka text mode mapping) */
plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);
mask = (1 << plane);
- if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {
+ if (sr(s, VGA_SEQ_PLANE_WRITE) & mask) {
addr = ((addr & ~1) << 1) | plane;
if (addr >= s->vram_size) {
return;
@@ -996,7 +1000,7 @@ void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)
do_write:
/* mask data according to sr[2] */
- mask = s->sr[VGA_SEQ_PLANE_WRITE];
+ mask = sr(s, VGA_SEQ_PLANE_WRITE);
s->plane_updated |= mask; /* only used to detect font change */
write_mask = mask16[mask];
if (addr * sizeof(uint32_t) >= s->vram_size) {
@@ -1152,10 +1156,10 @@ static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight
/* total width & height */
cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
cwidth = 8;
- if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
+ if (!(sr(s, VGA_SEQ_CLOCK_MODE) & VGA_SR01_CHAR_CLK_8DOTS)) {
cwidth = 9;
}
- if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
+ if (sr(s, VGA_SEQ_CLOCK_MODE) & 0x08) {
cwidth = 16; /* NOTE: no 18 pixel wide */
}
width = (s->cr[VGA_CRTC_H_DISP] + 1);
@@ -1197,7 +1201,7 @@ static void vga_draw_text(VGACommonState *s, int full_update)
int64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
/* compute font data address (in plane 2) */
- v = s->sr[VGA_SEQ_CHARACTER_MAP];
+ v = sr(s, VGA_SEQ_CHARACTER_MAP);
offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
if (offset != s->font_offsets[0]) {
s->font_offsets[0] = offset;
@@ -1506,11 +1510,11 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
}
if (shift_control == 0) {
- if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
+ if (sr(s, VGA_SEQ_CLOCK_MODE) & 8) {
disp_width <<= 1;
}
} else if (shift_control == 1) {
- if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
+ if (sr(s, VGA_SEQ_CLOCK_MODE) & 8) {
disp_width <<= 1;
}
}
@@ -1574,7 +1578,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
if (shift_control == 0) {
full_update |= update_palette16(s);
- if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
+ if (sr(s, VGA_SEQ_CLOCK_MODE) & 8) {
v = VGA_DRAW_LINE4D2;
} else {
v = VGA_DRAW_LINE4;
@@ -1582,7 +1586,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
bits = 4;
} else if (shift_control == 1) {
full_update |= update_palette16(s);
- if (s->sr[VGA_SEQ_CLOCK_MODE] & 8) {
+ if (sr(s, VGA_SEQ_CLOCK_MODE) & 8) {
v = VGA_DRAW_LINE2D2;
} else {
v = VGA_DRAW_LINE2;
@@ -1629,7 +1633,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
#if 0
printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
width, height, v, line_offset, s->cr[9], s->cr[VGA_CRTC_MODE],
- s->line_compare, s->sr[VGA_SEQ_CLOCK_MODE]);
+ s->line_compare, sr(s, VGA_SEQ_CLOCK_MODE));
#endif
addr1 = (s->start_addr * 4);
bwidth = (width * bits + 7) / 8;
@@ -1781,6 +1785,7 @@ void vga_common_reset(VGACommonState *s)
{
s->sr_index = 0;
memset(s->sr, '\0', sizeof(s->sr));
+ memset(s->sr_vbe, '\0', sizeof(s->sr_vbe));
s->gr_index = 0;
memset(s->gr, '\0', sizeof(s->gr));
s->ar_index = 0;
@@ -1883,10 +1888,10 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
/* total width & height */
cheight = (s->cr[VGA_CRTC_MAX_SCAN] & 0x1f) + 1;
cw = 8;
- if (!(s->sr[VGA_SEQ_CLOCK_MODE] & VGA_SR01_CHAR_CLK_8DOTS)) {
+ if (!(sr(s, VGA_SEQ_CLOCK_MODE) & VGA_SR01_CHAR_CLK_8DOTS)) {
cw = 9;
}
- if (s->sr[VGA_SEQ_CLOCK_MODE] & 0x08) {
+ if (sr(s, VGA_SEQ_CLOCK_MODE) & 0x08) {
cw = 16; /* NOTE: no 18 pixel wide */
}
width = (s->cr[VGA_CRTC_H_DISP] + 1);
@@ -2053,6 +2058,7 @@ static int vga_common_post_load(void *opaque, int version_id)
/* force refresh */
s->graphic_mode = -1;
+ vbe_update_vgaregs(s);
return 0;
}
diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h
index bdb43a5a34..3ce5544efd 100644
--- a/hw/display/vga_int.h
+++ b/hw/display/vga_int.h
@@ -98,6 +98,7 @@ typedef struct VGACommonState {
MemoryRegion chain4_alias;
uint8_t sr_index;
uint8_t sr[256];
+ uint8_t sr_vbe[256];
uint8_t gr_index;
uint8_t gr[256];
uint8_t ar_index;
diff --git a/hw/display/virtio-gpu-3d.c b/hw/display/virtio-gpu-3d.c
index fa192946a3..433bf93024 100644
--- a/hw/display/virtio-gpu-3d.c
+++ b/hw/display/virtio-gpu-3d.c
@@ -17,6 +17,7 @@
#include "trace.h"
#include "hw/virtio/virtio.h"
#include "hw/virtio/virtio-gpu.h"
+#include "qapi/error.h"
#ifdef CONFIG_VIRGL
@@ -127,7 +128,7 @@ static void virgl_cmd_resource_flush(VirtIOGPU *g,
trace_virtio_gpu_cmd_res_flush(rf.resource_id,
rf.r.width, rf.r.height, rf.r.x, rf.r.y);
- for (i = 0; i < VIRTIO_GPU_MAX_SCANOUT; i++) {
+ for (i = 0; i < g->conf.max_outputs; i++) {
if (g->scanout[i].resource_id != rf.resource_id) {
continue;
}
@@ -146,7 +147,7 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g,
trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
ss.r.width, ss.r.height, ss.r.x, ss.r.y);
- if (ss.scanout_id >= VIRTIO_GPU_MAX_SCANOUT) {
+ if (ss.scanout_id >= g->conf.max_outputs) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d",
__func__, ss.scanout_id);
cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 91345bd399..f3b0f1419e 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -20,6 +20,7 @@
#include "hw/virtio/virtio-gpu.h"
#include "hw/virtio/virtio-bus.h"
#include "qemu/log.h"
+#include "qapi/error.h"
static struct virtio_gpu_simple_resource*
virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id);
@@ -465,7 +466,7 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g,
pixman_region_init_rect(&flush_region,
rf.r.x, rf.r.y, rf.r.width, rf.r.height);
- for (i = 0; i < VIRTIO_GPU_MAX_SCANOUT; i++) {
+ for (i = 0; i < g->conf.max_outputs; i++) {
struct virtio_gpu_scanout *scanout;
pixman_region16_t region, finalregion;
pixman_box16_t *extents;
@@ -508,6 +509,13 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id,
ss.r.width, ss.r.height, ss.r.x, ss.r.y);
+ if (ss.scanout_id >= g->conf.max_outputs) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d",
+ __func__, ss.scanout_id);
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
+ return;
+ }
+
g->enable = 1;
if (ss.resource_id == 0) {
scanout = &g->scanout[ss.scanout_id];
@@ -517,8 +525,7 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
res->scanout_bitmask &= ~(1 << ss.scanout_id);
}
}
- if (ss.scanout_id == 0 ||
- ss.scanout_id >= g->conf.max_outputs) {
+ if (ss.scanout_id == 0) {
qemu_log_mask(LOG_GUEST_ERROR,
"%s: illegal scanout id specified %d",
__func__, ss.scanout_id);
@@ -533,14 +540,6 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
}
/* create a surface for this scanout */
- if (ss.scanout_id >= VIRTIO_GPU_MAX_SCANOUT ||
- ss.scanout_id >= g->conf.max_outputs) {
- qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal scanout id specified %d",
- __func__, ss.scanout_id);
- cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID;
- return;
- }
-
res = virtio_gpu_find_resource(g, ss.resource_id);
if (!res) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: illegal resource specified %d\n",
@@ -880,7 +879,7 @@ static int virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
{
VirtIOGPU *g = opaque;
- if (idx > g->conf.max_outputs) {
+ if (idx >= g->conf.max_outputs) {
return -1;
}
@@ -930,6 +929,11 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp)
bool have_virgl;
int i;
+ if (g->conf.max_outputs > VIRTIO_GPU_MAX_SCANOUTS) {
+ error_setg(errp, "invalid max_outputs > %d", VIRTIO_GPU_MAX_SCANOUTS);
+ return;
+ }
+
g->config_size = sizeof(struct virtio_gpu_config);
g->virtio_config.num_scanouts = g->conf.max_outputs;
virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU,
diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c
index e58b165ae5..f49f8deee7 100644
--- a/hw/display/virtio-vga.c
+++ b/hw/display/virtio-vga.c
@@ -4,6 +4,7 @@
#include "ui/console.h"
#include "vga_int.h"
#include "hw/virtio/virtio-pci.h"
+#include "qapi/error.h"
/*
* virtio-vga: This extends VirtioPCIProxy.
@@ -89,6 +90,7 @@ static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
VirtIOVGA *vvga = VIRTIO_VGA(vpci_dev);
VirtIOGPU *g = &vvga->vdev;
VGACommonState *vga = &vvga->vga;
+ Error *err = NULL;
uint32_t offset;
int i;
@@ -124,7 +126,11 @@ static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
/* force virtio-1.0 */
vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN;
vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY;
- object_property_set_bool(OBJECT(g), true, "realized", errp);
+ object_property_set_bool(OBJECT(g), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
+ }
/* add stdvga mmio regions */
pci_std_vga_mmio_region_init(vga, &vpci_dev->modern_bar,
diff --git a/hw/i386/kvmvapic.c b/hw/i386/kvmvapic.c
index 8fd27ba2f4..5b71b1ba46 100644
--- a/hw/i386/kvmvapic.c
+++ b/hw/i386/kvmvapic.c
@@ -397,7 +397,7 @@ static void patch_instruction(VAPICROMState *s, X86CPU *cpu, target_ulong ip)
CPUX86State *env = &cpu->env;
VAPICHandlers *handlers;
uint8_t opcode[2];
- uint32_t imm32;
+ uint32_t imm32 = 0;
target_ulong current_pc = 0;
target_ulong current_cs_base = 0;
uint32_t current_flags = 0;
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 99437e0b78..e29ccc8341 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -67,6 +67,7 @@
#include "qapi/visitor.h"
#include "qapi-visit.h"
#include "qom/cpu.h"
+#include "hw/nmi.h"
/* debug PC/ISA interrupts */
//#define DEBUG_IRQ
@@ -1963,11 +1964,28 @@ static CPUArchIdList *pc_possible_cpu_arch_ids(MachineState *machine)
return list;
}
+static void x86_nmi(NMIState *n, int cpu_index, Error **errp)
+{
+ /* cpu index isn't used */
+ CPUState *cs;
+
+ CPU_FOREACH(cs) {
+ X86CPU *cpu = X86_CPU(cs);
+
+ if (!cpu->apic_state) {
+ cpu_interrupt(cs, CPU_INTERRUPT_NMI);
+ } else {
+ apic_deliver_nmi(cpu->apic_state);
+ }
+ }
+}
+
static void pc_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
PCMachineClass *pcmc = PC_MACHINE_CLASS(oc);
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
+ NMIClass *nc = NMI_CLASS(oc);
pcmc->get_hotplug_handler = mc->get_hotplug_handler;
pcmc->pci_enabled = true;
@@ -1993,6 +2011,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
hc->plug = pc_machine_device_plug_cb;
hc->unplug_request = pc_machine_device_unplug_request_cb;
hc->unplug = pc_machine_device_unplug_cb;
+ nc->nmi_monitor_handler = x86_nmi;
}
static const TypeInfo pc_machine_info = {
@@ -2005,6 +2024,7 @@ static const TypeInfo pc_machine_info = {
.class_init = pc_machine_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_HOTPLUG_HANDLER },
+ { TYPE_NMI },
{ }
},
};
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 7f50116bc7..32918bb294 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -582,7 +582,6 @@ DEFINE_I440FX_MACHINE(v1_4, "pc-i440fx-1.4", pc_compat_1_4,
#define PC_COMPAT_1_3 \
- PC_COMPAT_1_4 \
{\
.driver = "usb-tablet",\
.property = "usb_version",\
@@ -614,7 +613,6 @@ DEFINE_I440FX_MACHINE(v1_3, "pc-1.3", pc_compat_1_3,
#define PC_COMPAT_1_2 \
- PC_COMPAT_1_3 \
{\
.driver = "nec-usb-xhci",\
.property = "msi",\
@@ -653,7 +651,6 @@ DEFINE_I440FX_MACHINE(v1_2, "pc-1.2", pc_compat_1_2,
#define PC_COMPAT_1_1 \
- PC_COMPAT_1_2 \
{\
.driver = "virtio-scsi-pci",\
.property = "hotplug",\
@@ -696,7 +693,6 @@ DEFINE_I440FX_MACHINE(v1_1, "pc-1.1", pc_compat_1_2,
#define PC_COMPAT_1_0 \
- PC_COMPAT_1_1 \
{\
.driver = TYPE_ISA_FDC,\
.property = "check_media_rate",\
@@ -726,14 +722,10 @@ DEFINE_I440FX_MACHINE(v1_0, "pc-1.0", pc_compat_1_2,
pc_i440fx_1_0_machine_options);
-#define PC_COMPAT_0_15 \
- PC_COMPAT_1_0
-
static void pc_i440fx_0_15_machine_options(MachineClass *m)
{
pc_i440fx_1_0_machine_options(m);
m->hw_version = "0.15";
- SET_MACHINE_COMPAT(m, PC_COMPAT_0_15);
}
DEFINE_I440FX_MACHINE(v0_15, "pc-0.15", pc_compat_1_2,
@@ -741,7 +733,6 @@ DEFINE_I440FX_MACHINE(v0_15, "pc-0.15", pc_compat_1_2,
#define PC_COMPAT_0_14 \
- PC_COMPAT_0_15 \
{\
.driver = "virtio-blk-pci",\
.property = "event_idx",\
@@ -780,7 +771,6 @@ DEFINE_I440FX_MACHINE(v0_14, "pc-0.14", pc_compat_1_2,
#define PC_COMPAT_0_13 \
- PC_COMPAT_0_14 \
{\
.driver = TYPE_PCI_DEVICE,\
.property = "command_serr_enable",\
@@ -817,7 +807,6 @@ DEFINE_I440FX_MACHINE(v0_13, "pc-0.13", pc_compat_0_13,
#define PC_COMPAT_0_12 \
- PC_COMPAT_0_13 \
{\
.driver = "virtio-serial-pci",\
.property = "max_ports",\
@@ -852,7 +841,6 @@ DEFINE_I440FX_MACHINE(v0_12, "pc-0.12", pc_compat_0_13,
#define PC_COMPAT_0_11 \
- PC_COMPAT_0_12 \
{\
.driver = "virtio-blk-pci",\
.property = "vectors",\
@@ -883,7 +871,6 @@ DEFINE_I440FX_MACHINE(v0_11, "pc-0.11", pc_compat_0_13,
#define PC_COMPAT_0_10 \
- PC_COMPAT_0_11 \
{\
.driver = "virtio-blk-pci",\
.property = "class",\
diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
index 4f42b911a2..273bb0854c 100644
--- a/hw/intc/ioapic.c
+++ b/hw/intc/ioapic.c
@@ -255,6 +255,34 @@ ioapic_mem_read(void *opaque, hwaddr addr, unsigned int size)
return val;
}
+/*
+ * This is to satisfy the hack in Linux kernel. One hack of it is to
+ * simulate clearing the Remote IRR bit of IOAPIC entry using the
+ * following:
+ *
+ * "For IO-APIC's with EOI register, we use that to do an explicit EOI.
+ * Otherwise, we simulate the EOI message manually by changing the trigger
+ * mode to edge and then back to level, with RTE being masked during
+ * this."
+ *
+ * (See linux kernel __eoi_ioapic_pin() comment in commit c0205701)
+ *
+ * This is based on the assumption that, Remote IRR bit will be
+ * cleared by IOAPIC hardware when configured as edge-triggered
+ * interrupts.
+ *
+ * Without this, level-triggered interrupts in IR mode might fail to
+ * work correctly.
+ */
+static inline void
+ioapic_fix_edge_remote_irr(uint64_t *entry)
+{
+ if (!(*entry & IOAPIC_LVT_TRIGGER_MODE)) {
+ /* Edge-triggered interrupts, make sure remote IRR is zero */
+ *entry &= ~((uint64_t)IOAPIC_LVT_REMOTE_IRR);
+ }
+}
+
static void
ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
unsigned int size)
@@ -281,6 +309,7 @@ ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
default:
index = (s->ioregsel - IOAPIC_REG_REDTBL_BASE) >> 1;
if (index >= 0 && index < IOAPIC_NUM_PINS) {
+ uint64_t ro_bits = s->ioredtbl[index] & IOAPIC_RO_BITS;
if (s->ioregsel & 1) {
s->ioredtbl[index] &= 0xffffffff;
s->ioredtbl[index] |= (uint64_t)val << 32;
@@ -288,6 +317,10 @@ ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
s->ioredtbl[index] &= ~0xffffffffULL;
s->ioredtbl[index] |= val;
}
+ /* restore RO bits */
+ s->ioredtbl[index] &= IOAPIC_RW_BITS;
+ s->ioredtbl[index] |= ro_bits;
+ ioapic_fix_edge_remote_irr(&s->ioredtbl[index]);
ioapic_service(s);
}
}
diff --git a/hw/lm32/milkymist-hw.h b/hw/lm32/milkymist-hw.h
index c8dfb4d2d4..f857d2846f 100644
--- a/hw/lm32/milkymist-hw.h
+++ b/hw/lm32/milkymist-hw.h
@@ -108,10 +108,6 @@ static inline DeviceState *milkymist_tmu2_create(hwaddr base,
int nelements;
int ver_major, ver_minor;
- if (display_type == DT_NOGRAPHIC) {
- return NULL;
- }
-
/* check that GLX will work */
d = XOpenDisplay(NULL);
if (d == NULL) {
diff --git a/hw/lm32/milkymist.c b/hw/lm32/milkymist.c
index 96e6f4dc2e..1abdf6e2e6 100644
--- a/hw/lm32/milkymist.c
+++ b/hw/lm32/milkymist.c
@@ -167,7 +167,9 @@ milkymist_init(MachineState *machine)
milkymist_memcard_create(0x60004000);
milkymist_ac97_create(0x60005000, irq[4], irq[5], irq[6], irq[7]);
milkymist_pfpu_create(0x60006000, irq[8]);
- milkymist_tmu2_create(0x60007000, irq[9]);
+ if (machine->enable_graphics) {
+ milkymist_tmu2_create(0x60007000, irq[9]);
+ }
milkymist_minimac2_create(0x60008000, 0x30000000, irq[10], irq[11]);
milkymist_softusb_create(0x6000f000, irq[15],
0x20000000, 0x1000, 0x20020000, 0x2000);
diff --git a/hw/net/opencores_eth.c b/hw/net/opencores_eth.c
index c6094fbb56..484d113eb6 100644
--- a/hw/net/opencores_eth.c
+++ b/hw/net/opencores_eth.c
@@ -33,6 +33,7 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
+#include "hw/net/mii.h"
#include "hw/sysbus.h"
#include "net/net.h"
#include "sysemu/sysemu.h"
@@ -55,12 +56,6 @@
/* PHY MII registers */
enum {
- MII_BMCR,
- MII_BMSR,
- MII_PHYIDR1,
- MII_PHYIDR2,
- MII_ANAR,
- MII_ANLPAR,
MII_REG_MAX = 16,
};
@@ -72,10 +67,11 @@ typedef struct Mii {
static void mii_set_link(Mii *s, bool link_ok)
{
if (link_ok) {
- s->regs[MII_BMSR] |= 0x4;
- s->regs[MII_ANLPAR] |= 0x01e1;
+ s->regs[MII_BMSR] |= MII_BMSR_LINK_ST;
+ s->regs[MII_ANLPAR] |= MII_ANLPAR_TXFD | MII_ANLPAR_TX |
+ MII_ANLPAR_10FD | MII_ANLPAR_10 | MII_ANLPAR_CSMACD;
} else {
- s->regs[MII_BMSR] &= ~0x4;
+ s->regs[MII_BMSR] &= ~MII_BMSR_LINK_ST;
s->regs[MII_ANLPAR] &= 0x01ff;
}
s->link_ok = link_ok;
@@ -84,11 +80,14 @@ static void mii_set_link(Mii *s, bool link_ok)
static void mii_reset(Mii *s)
{
memset(s->regs, 0, sizeof(s->regs));
- s->regs[MII_BMCR] = 0x1000;
- s->regs[MII_BMSR] = 0x7868; /* no ext regs */
- s->regs[MII_PHYIDR1] = 0x2000;
- s->regs[MII_PHYIDR2] = 0x5c90;
- s->regs[MII_ANAR] = 0x01e1;
+ s->regs[MII_BMCR] = MII_BMCR_AUTOEN;
+ s->regs[MII_BMSR] = MII_BMSR_100TX_FD | MII_BMSR_100TX_HD |
+ MII_BMSR_10T_FD | MII_BMSR_10T_HD | MII_BMSR_MFPS |
+ MII_BMSR_AN_COMP | MII_BMSR_AUTONEG;
+ s->regs[MII_PHYID1] = 0x2000;
+ s->regs[MII_PHYID2] = 0x5c90;
+ s->regs[MII_ANAR] = MII_ANAR_TXFD | MII_ANAR_TX |
+ MII_ANAR_10FD | MII_ANAR_10 | MII_ANAR_CSMACD;
mii_set_link(s, s->link_ok);
}
@@ -98,7 +97,7 @@ static void mii_ro(Mii *s, uint16_t v)
static void mii_write_bmcr(Mii *s, uint16_t v)
{
- if (v & 0x8000) {
+ if (v & MII_BMCR_RESET) {
mii_reset(s);
} else {
s->regs[MII_BMCR] = v;
@@ -110,8 +109,8 @@ static void mii_write_host(Mii *s, unsigned idx, uint16_t v)
static void (*reg_write[MII_REG_MAX])(Mii *s, uint16_t v) = {
[MII_BMCR] = mii_write_bmcr,
[MII_BMSR] = mii_ro,
- [MII_PHYIDR1] = mii_ro,
- [MII_PHYIDR2] = mii_ro,
+ [MII_PHYID1] = mii_ro,
+ [MII_PHYID2] = mii_ro,
};
if (idx < MII_REG_MAX) {
@@ -483,7 +482,8 @@ static NetClientInfo net_open_eth_info = {
static void open_eth_start_xmit(OpenEthState *s, desc *tx)
{
- uint8_t buf[65536];
+ uint8_t *buf = NULL;
+ uint8_t buffer[0x600];
unsigned len = GET_FIELD(tx->len_flags, TXD_LEN);
unsigned tx_len = len;
@@ -498,6 +498,11 @@ static void open_eth_start_xmit(OpenEthState *s, desc *tx)
trace_open_eth_start_xmit(tx->buf_ptr, len, tx_len);
+ if (tx_len > sizeof(buffer)) {
+ buf = g_new(uint8_t, tx_len);
+ } else {
+ buf = buffer;
+ }
if (len > tx_len) {
len = tx_len;
}
@@ -506,6 +511,9 @@ static void open_eth_start_xmit(OpenEthState *s, desc *tx)
memset(buf + len, 0, tx_len - len);
}
qemu_send_packet(qemu_get_queue(s->nic), buf, tx_len);
+ if (tx_len > sizeof(buffer)) {
+ g_free(buf);
+ }
if (tx->len_flags & TXD_WR) {
s->tx_desc = 0;
diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c
index 999f480280..cdbdfb5320 100644
--- a/hw/nvram/fw_cfg.c
+++ b/hw/nvram/fw_cfg.c
@@ -25,6 +25,7 @@
#include "hw/hw.h"
#include "sysemu/sysemu.h"
#include "sysemu/dma.h"
+#include "hw/boards.h"
#include "hw/isa/isa.h"
#include "hw/nvram/fw_cfg.h"
#include "hw/sysbus.h"
@@ -868,16 +869,17 @@ static void fw_cfg_machine_ready(struct Notifier *n, void *data)
static void fw_cfg_init1(DeviceState *dev)
{
FWCfgState *s = FW_CFG(dev);
+ MachineState *machine = MACHINE(qdev_get_machine());
assert(!object_resolve_path(FW_CFG_PATH, NULL));
- object_property_add_child(qdev_get_machine(), FW_CFG_NAME, OBJECT(s), NULL);
+ object_property_add_child(OBJECT(machine), FW_CFG_NAME, OBJECT(s), NULL);
qdev_init_nofail(dev);
fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4);
fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16);
- fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)(display_type == DT_NOGRAPHIC));
+ fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)!machine->enable_graphics);
fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)boot_menu);
fw_cfg_bootsplash(s);
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index de1de1d067..add68acfef 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -2387,7 +2387,6 @@ DEFINE_SPAPR_MACHINE(2_5, "2.5", false);
* pseries-2.4
*/
#define SPAPR_COMPAT_2_4 \
- SPAPR_COMPAT_2_5 \
HW_COMPAT_2_4
static void spapr_machine_2_4_instance_options(MachineState *machine)
@@ -2410,7 +2409,6 @@ DEFINE_SPAPR_MACHINE(2_4, "2.4", false);
* pseries-2.3
*/
#define SPAPR_COMPAT_2_3 \
- SPAPR_COMPAT_2_4 \
HW_COMPAT_2_3 \
{\
.driver = "spapr-pci-host-bridge",\
@@ -2438,7 +2436,6 @@ DEFINE_SPAPR_MACHINE(2_3, "2.3", false);
*/
#define SPAPR_COMPAT_2_2 \
- SPAPR_COMPAT_2_3 \
HW_COMPAT_2_2 \
{\
.driver = TYPE_SPAPR_PCI_HOST_BRIDGE,\
@@ -2463,7 +2460,6 @@ DEFINE_SPAPR_MACHINE(2_2, "2.2", false);
* pseries-2.1
*/
#define SPAPR_COMPAT_2_1 \
- SPAPR_COMPAT_2_2 \
HW_COMPAT_2_1
static void spapr_machine_2_1_instance_options(MachineState *machine)
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 18bbbfbbe2..95ff5e35ae 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -330,7 +330,6 @@ static const TypeInfo ccw_machine_info = {
HW_COMPAT_2_5
#define CCW_COMPAT_2_4 \
- CCW_COMPAT_2_5 \
HW_COMPAT_2_4 \
{\
.driver = TYPE_S390_SKEYS,\
diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c
index 8961be2f34..591c8172d5 100644
--- a/hw/scsi/esp.c
+++ b/hw/scsi/esp.c
@@ -82,7 +82,7 @@ void esp_request_cancelled(SCSIRequest *req)
}
}
-static uint32_t get_cmd(ESPState *s, uint8_t *buf)
+static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen)
{
uint32_t dmalen;
int target;
@@ -92,6 +92,9 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
dmalen = s->rregs[ESP_TCLO];
dmalen |= s->rregs[ESP_TCMID] << 8;
dmalen |= s->rregs[ESP_TCHI] << 16;
+ if (dmalen > buflen) {
+ return 0;
+ }
s->dma_memory_read(s->dma_opaque, buf, dmalen);
} else {
dmalen = s->ti_size;
@@ -166,7 +169,7 @@ static void handle_satn(ESPState *s)
s->dma_cb = handle_satn;
return;
}
- len = get_cmd(s, buf);
+ len = get_cmd(s, buf, sizeof(buf));
if (len)
do_cmd(s, buf);
}
@@ -180,7 +183,7 @@ static void handle_s_without_atn(ESPState *s)
s->dma_cb = handle_s_without_atn;
return;
}
- len = get_cmd(s, buf);
+ len = get_cmd(s, buf, sizeof(buf));
if (len) {
do_busid_cmd(s, buf, 0);
}
@@ -192,7 +195,7 @@ static void handle_satn_stop(ESPState *s)
s->dma_cb = handle_satn_stop;
return;
}
- s->cmdlen = get_cmd(s, s->cmdbuf);
+ s->cmdlen = get_cmd(s, s->cmdbuf, sizeof(s->cmdbuf));
if (s->cmdlen) {
trace_esp_handle_satn_stop(s->cmdlen);
s->do_cmd = 1;
@@ -448,7 +451,11 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
break;
case ESP_FIFO:
if (s->do_cmd) {
- s->cmdbuf[s->cmdlen++] = val & 0xff;
+ if (s->cmdlen < TI_BUFSZ) {
+ s->cmdbuf[s->cmdlen++] = val & 0xff;
+ } else {
+ trace_esp_error_fifo_overrun();
+ }
} else if (s->ti_size == TI_BUFSZ - 1) {
trace_esp_error_fifo_overrun();
} else {
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
index 7bfc00abc2..478fda8209 100644
--- a/hw/sparc/sun4m.c
+++ b/hw/sparc/sun4m.c
@@ -1000,7 +1000,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef,
slavio_timer_init_all(hwdef->counter_base, slavio_irq[19], slavio_cpu_irq, smp_cpus);
slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[14],
- display_type == DT_NOGRAPHIC, ESCC_CLOCK, 1);
+ !machine->enable_graphics, ESCC_CLOCK, 1);
/* Slavio TTYA (base+4, Linux ttyS0) is the first QEMU serial device
Slavio TTYB (base+0, Linux ttyS1) is the second QEMU serial device */
escc_init(hwdef->serial_base, slavio_irq[15], slavio_irq[15],
diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs
index 2717027d34..98b5c9d273 100644
--- a/hw/usb/Makefile.objs
+++ b/hw/usb/Makefile.objs
@@ -38,3 +38,7 @@ common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o
# usb pass-through
common-obj-y += $(patsubst %,host-%.o,$(HOST_USB))
+
+ifeq ($(CONFIG_USB_LIBUSB),y)
+common-obj-$(CONFIG_XEN_BACKEND) += xen-usb.o
+endif
diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c
index ffab561cf6..16d9ff7b4b 100644
--- a/hw/usb/hcd-ohci.c
+++ b/hw/usb/hcd-ohci.c
@@ -1848,6 +1848,12 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
ohci->as = as;
+ if (num_ports > OHCI_MAX_PORTS) {
+ error_setg(errp, "OHCI num-ports=%d is too big (limit is %d ports)",
+ num_ports, OHCI_MAX_PORTS);
+ return;
+ }
+
if (usb_frame_time == 0) {
#ifdef OHCI_TIME_WARP
usb_frame_time = NANOSECONDS_PER_SECOND;
diff --git a/hw/usb/xen-usb.c b/hw/usb/xen-usb.c
new file mode 100644
index 0000000000..664df04181
--- /dev/null
+++ b/hw/usb/xen-usb.c
@@ -0,0 +1,1080 @@
+/*
+ * xen paravirt usb device backend
+ *
+ * (c) Juergen Gross <jgross@suse.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; under version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Contributions after 2012-01-13 are licensed under the terms of the
+ * GNU GPL, version 2 or (at your option) any later version.
+ */
+
+#include <libusb.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/config-file.h"
+#include "hw/sysbus.h"
+#include "hw/usb.h"
+#include "hw/xen/xen_backend.h"
+#include "monitor/qdev.h"
+#include "qapi/qmp/qbool.h"
+#include "qapi/qmp/qint.h"
+#include "qapi/qmp/qstring.h"
+#include "sys/user.h"
+
+#include <xen/io/ring.h>
+#include <xen/io/usbif.h>
+
+/*
+ * Check for required support of usbif.h: USBIF_SHORT_NOT_OK was the last
+ * macro added we rely on.
+ */
+#ifdef USBIF_SHORT_NOT_OK
+
+#define TR(xendev, lvl, fmt, args...) \
+ { \
+ struct timeval tv; \
+ \
+ gettimeofday(&tv, NULL); \
+ xen_be_printf(xendev, lvl, "%8ld.%06ld xen-usb(%s):" fmt, \
+ tv.tv_sec, tv.tv_usec, __func__, ##args); \
+ }
+#define TR_BUS(xendev, fmt, args...) TR(xendev, 2, fmt, ##args)
+#define TR_REQ(xendev, fmt, args...) TR(xendev, 3, fmt, ##args)
+
+#define USBBACK_MAXPORTS USBIF_PIPE_PORT_MASK
+#define USB_DEV_ADDR_SIZE (USBIF_PIPE_DEV_MASK + 1)
+
+/* USB wire protocol: structure describing control request parameter. */
+struct usbif_ctrlrequest {
+ uint8_t bRequestType;
+ uint8_t bRequest;
+ uint16_t wValue;
+ uint16_t wIndex;
+ uint16_t wLength;
+};
+
+struct usbback_info;
+struct usbback_req;
+
+struct usbback_stub {
+ USBDevice *dev;
+ USBPort port;
+ unsigned int speed;
+ bool attached;
+ QTAILQ_HEAD(submit_q_head, usbback_req) submit_q;
+};
+
+struct usbback_req {
+ struct usbback_info *usbif;
+ struct usbback_stub *stub;
+ struct usbif_urb_request req;
+ USBPacket packet;
+
+ unsigned int nr_buffer_segs; /* # of transfer_buffer segments */
+ unsigned int nr_extra_segs; /* # of iso_frame_desc segments */
+
+ QTAILQ_ENTRY(usbback_req) q;
+
+ void *buffer;
+ void *isoc_buffer;
+ struct libusb_transfer *xfer;
+};
+
+struct usbback_hotplug {
+ QSIMPLEQ_ENTRY(usbback_hotplug) q;
+ unsigned port;
+};
+
+struct usbback_info {
+ struct XenDevice xendev; /* must be first */
+ USBBus bus;
+ void *urb_sring;
+ void *conn_sring;
+ struct usbif_urb_back_ring urb_ring;
+ struct usbif_conn_back_ring conn_ring;
+ int num_ports;
+ int usb_ver;
+ bool ring_error;
+ QTAILQ_HEAD(req_free_q_head, usbback_req) req_free_q;
+ QSIMPLEQ_HEAD(hotplug_q_head, usbback_hotplug) hotplug_q;
+ struct usbback_stub ports[USBBACK_MAXPORTS];
+ struct usbback_stub *addr_table[USB_DEV_ADDR_SIZE];
+ QEMUBH *bh;
+};
+
+static struct usbback_req *usbback_get_req(struct usbback_info *usbif)
+{
+ struct usbback_req *usbback_req;
+
+ if (QTAILQ_EMPTY(&usbif->req_free_q)) {
+ usbback_req = g_new0(struct usbback_req, 1);
+ } else {
+ usbback_req = QTAILQ_FIRST(&usbif->req_free_q);
+ QTAILQ_REMOVE(&usbif->req_free_q, usbback_req, q);
+ }
+ return usbback_req;
+}
+
+static void usbback_put_req(struct usbback_req *usbback_req)
+{
+ struct usbback_info *usbif;
+
+ usbif = usbback_req->usbif;
+ memset(usbback_req, 0, sizeof(*usbback_req));
+ QTAILQ_INSERT_HEAD(&usbif->req_free_q, usbback_req, q);
+}
+
+static int usbback_gnttab_map(struct usbback_req *usbback_req)
+{
+ unsigned int nr_segs, i, prot;
+ uint32_t ref[USBIF_MAX_SEGMENTS_PER_REQUEST];
+ struct usbback_info *usbif = usbback_req->usbif;
+ struct XenDevice *xendev = &usbif->xendev;
+ struct usbif_request_segment *seg;
+ void *addr;
+
+ nr_segs = usbback_req->nr_buffer_segs + usbback_req->nr_extra_segs;
+ if (!nr_segs) {
+ return 0;
+ }
+
+ if (nr_segs > USBIF_MAX_SEGMENTS_PER_REQUEST) {
+ xen_be_printf(xendev, 0, "bad number of segments in request (%d)\n",
+ nr_segs);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < nr_segs; i++) {
+ if ((unsigned)usbback_req->req.seg[i].offset +
+ (unsigned)usbback_req->req.seg[i].length > PAGE_SIZE) {
+ xen_be_printf(xendev, 0, "segment crosses page boundary\n");
+ return -EINVAL;
+ }
+ }
+
+ if (usbback_req->nr_buffer_segs) {
+ prot = PROT_READ;
+ if (usbif_pipein(usbback_req->req.pipe)) {
+ prot |= PROT_WRITE;
+ }
+ for (i = 0; i < usbback_req->nr_buffer_segs; i++) {
+ ref[i] = usbback_req->req.seg[i].gref;
+ }
+ usbback_req->buffer = xengnttab_map_domain_grant_refs(xendev->gnttabdev,
+ usbback_req->nr_buffer_segs, xendev->dom, ref, prot);
+
+ if (!usbback_req->buffer) {
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < usbback_req->nr_buffer_segs; i++) {
+ seg = usbback_req->req.seg + i;
+ addr = usbback_req->buffer + i * PAGE_SIZE + seg->offset;
+ qemu_iovec_add(&usbback_req->packet.iov, addr, seg->length);
+ }
+ }
+
+ if (!usbif_pipeisoc(usbback_req->req.pipe)) {
+ return 0;
+ }
+
+ /*
+ * Right now isoc requests are not supported.
+ * Prepare supporting those by doing the work needed on the guest
+ * interface side.
+ */
+
+ if (!usbback_req->nr_extra_segs) {
+ xen_be_printf(xendev, 0, "iso request without descriptor segments\n");
+ return -EINVAL;
+ }
+
+ prot = PROT_READ | PROT_WRITE;
+ for (i = 0; i < usbback_req->nr_extra_segs; i++) {
+ ref[i] = usbback_req->req.seg[i + usbback_req->req.nr_buffer_segs].gref;
+ }
+ usbback_req->isoc_buffer = xengnttab_map_domain_grant_refs(
+ xendev->gnttabdev, usbback_req->nr_extra_segs, xendev->dom, ref, prot);
+
+ if (!usbback_req->isoc_buffer) {
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static int usbback_init_packet(struct usbback_req *usbback_req)
+{
+ struct XenDevice *xendev = &usbback_req->usbif->xendev;
+ USBPacket *packet = &usbback_req->packet;
+ USBDevice *dev = usbback_req->stub->dev;
+ USBEndpoint *ep;
+ unsigned int pid, ep_nr;
+ bool sok;
+ int ret = 0;
+
+ qemu_iovec_init(&packet->iov, USBIF_MAX_SEGMENTS_PER_REQUEST);
+ pid = usbif_pipein(usbback_req->req.pipe) ? USB_TOKEN_IN : USB_TOKEN_OUT;
+ ep_nr = usbif_pipeendpoint(usbback_req->req.pipe);
+ sok = !!(usbback_req->req.transfer_flags & USBIF_SHORT_NOT_OK);
+ if (usbif_pipectrl(usbback_req->req.pipe)) {
+ ep_nr = 0;
+ sok = false;
+ }
+ ep = usb_ep_get(dev, pid, ep_nr);
+ usb_packet_setup(packet, pid, ep, 0, 1, sok, true);
+
+ switch (usbif_pipetype(usbback_req->req.pipe)) {
+ case USBIF_PIPE_TYPE_ISOC:
+ TR_REQ(xendev, "iso transfer %s: buflen: %x, %d frames\n",
+ (pid == USB_TOKEN_IN) ? "in" : "out",
+ usbback_req->req.buffer_length,
+ usbback_req->req.u.isoc.nr_frame_desc_segs);
+ ret = -EINVAL; /* isoc not implemented yet */
+ break;
+
+ case USBIF_PIPE_TYPE_INT:
+ TR_REQ(xendev, "int transfer %s: buflen: %x\n",
+ (pid == USB_TOKEN_IN) ? "in" : "out",
+ usbback_req->req.buffer_length);
+ break;
+
+ case USBIF_PIPE_TYPE_CTRL:
+ packet->parameter = *(uint64_t *)usbback_req->req.u.ctrl;
+ TR_REQ(xendev, "ctrl parameter: %lx, buflen: %x\n", packet->parameter,
+ usbback_req->req.buffer_length);
+ break;
+
+ case USBIF_PIPE_TYPE_BULK:
+ TR_REQ(xendev, "bulk transfer %s: buflen: %x\n",
+ (pid == USB_TOKEN_IN) ? "in" : "out",
+ usbback_req->req.buffer_length);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static void usbback_do_response(struct usbback_req *usbback_req, int32_t status,
+ int32_t actual_length, int32_t error_count)
+{
+ struct usbback_info *usbif;
+ struct usbif_urb_response *res;
+ struct XenDevice *xendev;
+ unsigned int notify;
+
+ usbif = usbback_req->usbif;
+ xendev = &usbif->xendev;
+
+ TR_REQ(xendev, "id %d, status %d, length %d, errcnt %d\n",
+ usbback_req->req.id, status, actual_length, error_count);
+
+ if (usbback_req->packet.iov.iov) {
+ qemu_iovec_destroy(&usbback_req->packet.iov);
+ }
+
+ if (usbback_req->buffer) {
+ xengnttab_unmap(xendev->gnttabdev, usbback_req->buffer,
+ usbback_req->nr_buffer_segs);
+ usbback_req->buffer = NULL;
+ }
+
+ if (usbback_req->isoc_buffer) {
+ xengnttab_unmap(xendev->gnttabdev, usbback_req->isoc_buffer,
+ usbback_req->nr_extra_segs);
+ usbback_req->isoc_buffer = NULL;
+ }
+
+ res = RING_GET_RESPONSE(&usbif->urb_ring, usbif->urb_ring.rsp_prod_pvt);
+ res->id = usbback_req->req.id;
+ res->status = status;
+ res->actual_length = actual_length;
+ res->error_count = error_count;
+ res->start_frame = 0;
+ usbif->urb_ring.rsp_prod_pvt++;
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&usbif->urb_ring, notify);
+
+ if (notify) {
+ xen_be_send_notify(xendev);
+ }
+
+ usbback_put_req(usbback_req);
+}
+
+static void usbback_do_response_ret(struct usbback_req *usbback_req,
+ int32_t status)
+{
+ usbback_do_response(usbback_req, status, 0, 0);
+}
+
+static int32_t usbback_xlat_status(int status)
+{
+ switch (status) {
+ case USB_RET_SUCCESS:
+ return 0;
+ case USB_RET_NODEV:
+ return -ENODEV;
+ case USB_RET_STALL:
+ return -EPIPE;
+ case USB_RET_BABBLE:
+ return -EOVERFLOW;
+ case USB_RET_IOERROR:
+ return -EPROTO;
+ }
+
+ return -ESHUTDOWN;
+}
+
+static void usbback_packet_complete(USBPacket *packet)
+{
+ struct usbback_req *usbback_req;
+ int32_t status;
+
+ usbback_req = container_of(packet, struct usbback_req, packet);
+
+ QTAILQ_REMOVE(&usbback_req->stub->submit_q, usbback_req, q);
+
+ status = usbback_xlat_status(packet->status);
+ usbback_do_response(usbback_req, status, packet->actual_length, 0);
+}
+
+static void usbback_set_address(struct usbback_info *usbif,
+ struct usbback_stub *stub,
+ unsigned int cur_addr, unsigned int new_addr)
+{
+ if (cur_addr) {
+ usbif->addr_table[cur_addr] = NULL;
+ }
+ if (new_addr) {
+ usbif->addr_table[new_addr] = stub;
+ }
+}
+
+static bool usbback_cancel_req(struct usbback_req *usbback_req)
+{
+ bool ret = false;
+
+ if (usb_packet_is_inflight(&usbback_req->packet)) {
+ usb_cancel_packet(&usbback_req->packet);
+ ret = true;
+ }
+ return ret;
+}
+
+static void usbback_process_unlink_req(struct usbback_req *usbback_req)
+{
+ struct usbback_info *usbif;
+ struct usbback_req *unlink_req;
+ unsigned int id, devnum;
+ int ret;
+
+ usbif = usbback_req->usbif;
+ ret = 0;
+ id = usbback_req->req.u.unlink.unlink_id;
+ TR_REQ(&usbif->xendev, "unlink id %d\n", id);
+ devnum = usbif_pipedevice(usbback_req->req.pipe);
+ if (unlikely(devnum == 0)) {
+ usbback_req->stub = usbif->ports +
+ usbif_pipeportnum(usbback_req->req.pipe);
+ if (unlikely(!usbback_req->stub)) {
+ ret = -ENODEV;
+ goto fail_response;
+ }
+ } else {
+ if (unlikely(!usbif->addr_table[devnum])) {
+ ret = -ENODEV;
+ goto fail_response;
+ }
+ usbback_req->stub = usbif->addr_table[devnum];
+ }
+
+ QTAILQ_FOREACH(unlink_req, &usbback_req->stub->submit_q, q) {
+ if (unlink_req->req.id == id) {
+ if (usbback_cancel_req(unlink_req)) {
+ usbback_do_response_ret(unlink_req, -EPROTO);
+ }
+ break;
+ }
+ }
+
+fail_response:
+ usbback_do_response_ret(usbback_req, ret);
+}
+
+/*
+ * Checks whether a request can be handled at once or should be forwarded
+ * to the usb framework.
+ * Return value is:
+ * 0 in case of usb framework is needed
+ * 1 in case of local handling (no error)
+ * The request response has been queued already if return value not 0.
+ */
+static int usbback_check_and_submit(struct usbback_req *usbback_req)
+{
+ struct usbback_info *usbif;
+ unsigned int devnum;
+ struct usbback_stub *stub;
+ struct usbif_ctrlrequest *ctrl;
+ int ret;
+ uint16_t wValue;
+
+ usbif = usbback_req->usbif;
+ stub = NULL;
+ devnum = usbif_pipedevice(usbback_req->req.pipe);
+ ctrl = (struct usbif_ctrlrequest *)usbback_req->req.u.ctrl;
+ wValue = le16_to_cpu(ctrl->wValue);
+
+ /*
+ * When the device is first connected or resetted, USB device has no
+ * address. In this initial state, following requests are sent to device
+ * address (#0),
+ *
+ * 1. GET_DESCRIPTOR (with Descriptor Type is "DEVICE") is sent,
+ * and OS knows what device is connected to.
+ *
+ * 2. SET_ADDRESS is sent, and then device has its address.
+ *
+ * In the next step, SET_CONFIGURATION is sent to addressed device, and
+ * then the device is finally ready to use.
+ */
+ if (unlikely(devnum == 0)) {
+ stub = usbif->ports + usbif_pipeportnum(usbback_req->req.pipe) - 1;
+ if (!stub->dev || !stub->attached) {
+ ret = -ENODEV;
+ goto do_response;
+ }
+
+ switch (ctrl->bRequest) {
+ case USB_REQ_GET_DESCRIPTOR:
+ /*
+ * GET_DESCRIPTOR request to device #0.
+ * through normal transfer.
+ */
+ TR_REQ(&usbif->xendev, "devnum 0 GET_DESCRIPTOR\n");
+ usbback_req->stub = stub;
+ return 0;
+ case USB_REQ_SET_ADDRESS:
+ /*
+ * SET_ADDRESS request to device #0.
+ * add attached device to addr_table.
+ */
+ TR_REQ(&usbif->xendev, "devnum 0 SET_ADDRESS\n");
+ usbback_set_address(usbif, stub, 0, wValue);
+ ret = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ goto do_response;
+ }
+
+ if (unlikely(!usbif->addr_table[devnum])) {
+ ret = -ENODEV;
+ goto do_response;
+ }
+ usbback_req->stub = usbif->addr_table[devnum];
+
+ /*
+ * Check special request
+ */
+ if (ctrl->bRequest != USB_REQ_SET_ADDRESS) {
+ return 0;
+ }
+
+ /*
+ * SET_ADDRESS request to addressed device.
+ * change addr or remove from addr_table.
+ */
+ usbback_set_address(usbif, usbback_req->stub, devnum, wValue);
+ ret = 0;
+
+do_response:
+ usbback_do_response_ret(usbback_req, ret);
+ return 1;
+}
+
+static void usbback_dispatch(struct usbback_req *usbback_req)
+{
+ int ret;
+ unsigned int devnum;
+ struct usbback_info *usbif;
+
+ usbif = usbback_req->usbif;
+
+ TR_REQ(&usbif->xendev, "start req_id %d pipe %08x\n", usbback_req->req.id,
+ usbback_req->req.pipe);
+
+ /* unlink request */
+ if (unlikely(usbif_pipeunlink(usbback_req->req.pipe))) {
+ usbback_process_unlink_req(usbback_req);
+ return;
+ }
+
+ if (usbif_pipectrl(usbback_req->req.pipe)) {
+ if (usbback_check_and_submit(usbback_req)) {
+ return;
+ }
+ } else {
+ devnum = usbif_pipedevice(usbback_req->req.pipe);
+ usbback_req->stub = usbif->addr_table[devnum];
+
+ if (!usbback_req->stub || !usbback_req->stub->attached) {
+ ret = -ENODEV;
+ goto fail_response;
+ }
+ }
+
+ QTAILQ_INSERT_TAIL(&usbback_req->stub->submit_q, usbback_req, q);
+
+ usbback_req->nr_buffer_segs = usbback_req->req.nr_buffer_segs;
+ usbback_req->nr_extra_segs = usbif_pipeisoc(usbback_req->req.pipe) ?
+ usbback_req->req.u.isoc.nr_frame_desc_segs : 0;
+
+ ret = usbback_init_packet(usbback_req);
+ if (ret) {
+ xen_be_printf(&usbif->xendev, 0, "invalid request\n");
+ ret = -ESHUTDOWN;
+ goto fail_free_urb;
+ }
+
+ ret = usbback_gnttab_map(usbback_req);
+ if (ret) {
+ xen_be_printf(&usbif->xendev, 0, "invalid buffer, ret=%d\n", ret);
+ ret = -ESHUTDOWN;
+ goto fail_free_urb;
+ }
+
+ usb_handle_packet(usbback_req->stub->dev, &usbback_req->packet);
+ if (usbback_req->packet.status != USB_RET_ASYNC) {
+ usbback_packet_complete(&usbback_req->packet);
+ }
+ return;
+
+fail_free_urb:
+ QTAILQ_REMOVE(&usbback_req->stub->submit_q, usbback_req, q);
+
+fail_response:
+ usbback_do_response_ret(usbback_req, ret);
+}
+
+static void usbback_hotplug_notify(struct usbback_info *usbif)
+{
+ struct usbif_conn_back_ring *ring = &usbif->conn_ring;
+ struct usbif_conn_request req;
+ struct usbif_conn_response *res;
+ struct usbback_hotplug *usb_hp;
+ unsigned int notify;
+
+ if (!usbif->conn_sring) {
+ return;
+ }
+
+ /* Check for full ring. */
+ if ((RING_SIZE(ring) - ring->rsp_prod_pvt - ring->req_cons) == 0) {
+ xen_be_send_notify(&usbif->xendev);
+ return;
+ }
+
+ usb_hp = QSIMPLEQ_FIRST(&usbif->hotplug_q);
+ QSIMPLEQ_REMOVE_HEAD(&usbif->hotplug_q, q);
+
+ RING_COPY_REQUEST(ring, ring->req_cons, &req);
+ ring->req_cons++;
+ ring->sring->req_event = ring->req_cons + 1;
+
+ res = RING_GET_RESPONSE(ring, ring->rsp_prod_pvt);
+ res->id = req.id;
+ res->portnum = usb_hp->port;
+ res->speed = usbif->ports[usb_hp->port - 1].speed;
+ ring->rsp_prod_pvt++;
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(ring, notify);
+
+ if (notify) {
+ xen_be_send_notify(&usbif->xendev);
+ }
+
+ TR_BUS(&usbif->xendev, "hotplug port %d speed %d\n", usb_hp->port,
+ res->speed);
+
+ g_free(usb_hp);
+
+ if (!QSIMPLEQ_EMPTY(&usbif->hotplug_q)) {
+ qemu_bh_schedule(usbif->bh);
+ }
+}
+
+static void usbback_bh(void *opaque)
+{
+ struct usbback_info *usbif;
+ struct usbif_urb_back_ring *urb_ring;
+ struct usbback_req *usbback_req;
+ RING_IDX rc, rp;
+ unsigned int more_to_do;
+
+ usbif = opaque;
+ if (usbif->ring_error) {
+ return;
+ }
+
+ if (!QSIMPLEQ_EMPTY(&usbif->hotplug_q)) {
+ usbback_hotplug_notify(usbif);
+ }
+
+ urb_ring = &usbif->urb_ring;
+ rc = urb_ring->req_cons;
+ rp = urb_ring->sring->req_prod;
+ xen_rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+ if (RING_REQUEST_PROD_OVERFLOW(urb_ring, rp)) {
+ rc = urb_ring->rsp_prod_pvt;
+ xen_be_printf(&usbif->xendev, 0, "domU provided bogus ring requests "
+ "(%#x - %#x = %u). Halting ring processing.\n",
+ rp, rc, rp - rc);
+ usbif->ring_error = true;
+ return;
+ }
+
+ while (rc != rp) {
+ if (RING_REQUEST_CONS_OVERFLOW(urb_ring, rc)) {
+ break;
+ }
+ usbback_req = usbback_get_req(usbif);
+
+ RING_COPY_REQUEST(urb_ring, rc, &usbback_req->req);
+ usbback_req->usbif = usbif;
+
+ usbback_dispatch(usbback_req);
+
+ urb_ring->req_cons = ++rc;
+ }
+
+ RING_FINAL_CHECK_FOR_REQUESTS(urb_ring, more_to_do);
+ if (more_to_do) {
+ qemu_bh_schedule(usbif->bh);
+ }
+}
+
+static void usbback_hotplug_enq(struct usbback_info *usbif, unsigned port)
+{
+ struct usbback_hotplug *usb_hp;
+
+ usb_hp = g_new0(struct usbback_hotplug, 1);
+ usb_hp->port = port;
+ QSIMPLEQ_INSERT_TAIL(&usbif->hotplug_q, usb_hp, q);
+ usbback_hotplug_notify(usbif);
+}
+
+static void usbback_portid_remove(struct usbback_info *usbif, unsigned port)
+{
+ USBPort *p;
+
+ if (!usbif->ports[port - 1].dev) {
+ return;
+ }
+
+ p = &(usbif->ports[port - 1].port);
+ snprintf(p->path, sizeof(p->path), "%d", 99);
+
+ object_unparent(OBJECT(usbif->ports[port - 1].dev));
+ usbif->ports[port - 1].dev = NULL;
+ usbif->ports[port - 1].speed = USBIF_SPEED_NONE;
+ usbif->ports[port - 1].attached = false;
+ usbback_hotplug_enq(usbif, port);
+
+ TR_BUS(&usbif->xendev, "port %d removed\n", port);
+}
+
+static void usbback_portid_add(struct usbback_info *usbif, unsigned port,
+ char *busid)
+{
+ unsigned speed;
+ char *portname;
+ USBPort *p;
+ Error *local_err = NULL;
+ QDict *qdict;
+ QemuOpts *opts;
+
+ if (usbif->ports[port - 1].dev) {
+ return;
+ }
+
+ portname = strchr(busid, '-');
+ if (!portname) {
+ xen_be_printf(&usbif->xendev, 0, "device %s illegal specification\n",
+ busid);
+ return;
+ }
+ portname++;
+ p = &(usbif->ports[port - 1].port);
+ snprintf(p->path, sizeof(p->path), "%s", portname);
+
+ qdict = qdict_new();
+ qdict_put(qdict, "driver", qstring_from_str("usb-host"));
+ qdict_put(qdict, "hostbus", qint_from_int(atoi(busid)));
+ qdict_put(qdict, "hostport", qstring_from_str(portname));
+ opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, &local_err);
+ if (local_err) {
+ goto err;
+ }
+ usbif->ports[port - 1].dev = USB_DEVICE(qdev_device_add(opts, &local_err));
+ if (!usbif->ports[port - 1].dev) {
+ goto err;
+ }
+ QDECREF(qdict);
+ snprintf(p->path, sizeof(p->path), "%d", port);
+ speed = usbif->ports[port - 1].dev->speed;
+ switch (speed) {
+ case USB_SPEED_LOW:
+ speed = USBIF_SPEED_LOW;
+ break;
+ case USB_SPEED_FULL:
+ speed = USBIF_SPEED_FULL;
+ break;
+ case USB_SPEED_HIGH:
+ speed = (usbif->usb_ver < USB_VER_USB20) ?
+ USBIF_SPEED_NONE : USBIF_SPEED_HIGH;
+ break;
+ default:
+ speed = USBIF_SPEED_NONE;
+ break;
+ }
+ if (speed == USBIF_SPEED_NONE) {
+ xen_be_printf(&usbif->xendev, 0, "device %s wrong speed\n", busid);
+ object_unparent(OBJECT(usbif->ports[port - 1].dev));
+ usbif->ports[port - 1].dev = NULL;
+ return;
+ }
+ usb_device_reset(usbif->ports[port - 1].dev);
+ usbif->ports[port - 1].speed = speed;
+ usbif->ports[port - 1].attached = true;
+ QTAILQ_INIT(&usbif->ports[port - 1].submit_q);
+ usbback_hotplug_enq(usbif, port);
+
+ TR_BUS(&usbif->xendev, "port %d attached\n", port);
+ return;
+
+err:
+ QDECREF(qdict);
+ snprintf(p->path, sizeof(p->path), "%d", 99);
+ xen_be_printf(&usbif->xendev, 0, "device %s could not be opened\n", busid);
+}
+
+static void usbback_process_port(struct usbback_info *usbif, unsigned port)
+{
+ char node[8];
+ char *busid;
+
+ snprintf(node, sizeof(node), "port/%d", port);
+ busid = xenstore_read_be_str(&usbif->xendev, node);
+ if (busid == NULL) {
+ xen_be_printf(&usbif->xendev, 0, "xenstore_read %s failed\n", node);
+ return;
+ }
+
+ /* Remove portid, if the port is not connected. */
+ if (strlen(busid) == 0) {
+ usbback_portid_remove(usbif, port);
+ } else {
+ usbback_portid_add(usbif, port, busid);
+ }
+
+ g_free(busid);
+}
+
+static void usbback_disconnect(struct XenDevice *xendev)
+{
+ struct usbback_info *usbif;
+ struct usbback_req *req, *tmp;
+ unsigned int i;
+
+ TR_BUS(xendev, "start\n");
+
+ usbif = container_of(xendev, struct usbback_info, xendev);
+
+ xen_be_unbind_evtchn(xendev);
+
+ if (usbif->urb_sring) {
+ xengnttab_unmap(xendev->gnttabdev, usbif->urb_sring, 1);
+ usbif->urb_sring = NULL;
+ }
+ if (usbif->conn_sring) {
+ xengnttab_unmap(xendev->gnttabdev, usbif->conn_sring, 1);
+ usbif->conn_sring = NULL;
+ }
+
+ for (i = 0; i < usbif->num_ports; i++) {
+ if (!usbif->ports[i].dev) {
+ continue;
+ }
+ QTAILQ_FOREACH_SAFE(req, &usbif->ports[i].submit_q, q, tmp) {
+ usbback_cancel_req(req);
+ }
+ }
+
+ TR_BUS(xendev, "finished\n");
+}
+
+static int usbback_connect(struct XenDevice *xendev)
+{
+ struct usbback_info *usbif;
+ struct usbif_urb_sring *urb_sring;
+ struct usbif_conn_sring *conn_sring;
+ int urb_ring_ref;
+ int conn_ring_ref;
+ unsigned int i;
+
+ TR_BUS(xendev, "start\n");
+
+ usbif = container_of(xendev, struct usbback_info, xendev);
+
+ if (xenstore_read_fe_int(xendev, "urb-ring-ref", &urb_ring_ref)) {
+ xen_be_printf(xendev, 0, "error reading urb-ring-ref\n");
+ return -1;
+ }
+ if (xenstore_read_fe_int(xendev, "conn-ring-ref", &conn_ring_ref)) {
+ xen_be_printf(xendev, 0, "error reading conn-ring-ref\n");
+ return -1;
+ }
+ if (xenstore_read_fe_int(xendev, "event-channel", &xendev->remote_port)) {
+ xen_be_printf(xendev, 0, "error reading event-channel\n");
+ return -1;
+ }
+
+ usbif->urb_sring = xengnttab_map_grant_ref(xendev->gnttabdev, xendev->dom,
+ urb_ring_ref,
+ PROT_READ | PROT_WRITE);
+ usbif->conn_sring = xengnttab_map_grant_ref(xendev->gnttabdev, xendev->dom,
+ conn_ring_ref,
+ PROT_READ | PROT_WRITE);
+ if (!usbif->urb_sring || !usbif->conn_sring) {
+ xen_be_printf(xendev, 0, "error mapping rings\n");
+ usbback_disconnect(xendev);
+ return -1;
+ }
+
+ urb_sring = usbif->urb_sring;
+ conn_sring = usbif->conn_sring;
+ BACK_RING_INIT(&usbif->urb_ring, urb_sring, XC_PAGE_SIZE);
+ BACK_RING_INIT(&usbif->conn_ring, conn_sring, XC_PAGE_SIZE);
+
+ xen_be_bind_evtchn(xendev);
+
+ xen_be_printf(xendev, 1, "urb-ring-ref %d, conn-ring-ref %d, "
+ "remote port %d, local port %d\n", urb_ring_ref,
+ conn_ring_ref, xendev->remote_port, xendev->local_port);
+
+ for (i = 1; i <= usbif->num_ports; i++) {
+ if (usbif->ports[i - 1].dev) {
+ usbback_hotplug_enq(usbif, i);
+ }
+ }
+
+ return 0;
+}
+
+static void usbback_backend_changed(struct XenDevice *xendev, const char *node)
+{
+ struct usbback_info *usbif;
+ unsigned int i;
+
+ TR_BUS(xendev, "path %s\n", node);
+
+ usbif = container_of(xendev, struct usbback_info, xendev);
+ for (i = 1; i <= usbif->num_ports; i++) {
+ usbback_process_port(usbif, i);
+ }
+}
+
+static int usbback_init(struct XenDevice *xendev)
+{
+ struct usbback_info *usbif;
+
+ TR_BUS(xendev, "start\n");
+
+ usbif = container_of(xendev, struct usbback_info, xendev);
+
+ if (xenstore_read_be_int(xendev, "num-ports", &usbif->num_ports) ||
+ usbif->num_ports < 1 || usbif->num_ports > USBBACK_MAXPORTS) {
+ xen_be_printf(xendev, 0, "num-ports not readable or out of bounds\n");
+ return -1;
+ }
+ if (xenstore_read_be_int(xendev, "usb-ver", &usbif->usb_ver) ||
+ (usbif->usb_ver != USB_VER_USB11 && usbif->usb_ver != USB_VER_USB20)) {
+ xen_be_printf(xendev, 0, "usb-ver not readable or out of bounds\n");
+ return -1;
+ }
+
+ usbback_backend_changed(xendev, "port");
+
+ TR_BUS(xendev, "finished\n");
+
+ return 0;
+}
+
+static void xen_bus_attach(USBPort *port)
+{
+ struct usbback_info *usbif;
+
+ usbif = port->opaque;
+ TR_BUS(&usbif->xendev, "\n");
+ usbif->ports[port->index].attached = true;
+ usbback_hotplug_enq(usbif, port->index + 1);
+}
+
+static void xen_bus_detach(USBPort *port)
+{
+ struct usbback_info *usbif;
+
+ usbif = port->opaque;
+ TR_BUS(&usbif->xendev, "\n");
+ usbif->ports[port->index].attached = false;
+ usbback_hotplug_enq(usbif, port->index + 1);
+}
+
+static void xen_bus_child_detach(USBPort *port, USBDevice *child)
+{
+ struct usbback_info *usbif;
+
+ usbif = port->opaque;
+ TR_BUS(&usbif->xendev, "\n");
+}
+
+static void xen_bus_complete(USBPort *port, USBPacket *packet)
+{
+ struct usbback_info *usbif;
+
+ usbif = port->opaque;
+ TR_REQ(&usbif->xendev, "\n");
+ usbback_packet_complete(packet);
+}
+
+static USBPortOps xen_usb_port_ops = {
+ .attach = xen_bus_attach,
+ .detach = xen_bus_detach,
+ .child_detach = xen_bus_child_detach,
+ .complete = xen_bus_complete,
+};
+
+static USBBusOps xen_usb_bus_ops = {
+};
+
+static void usbback_alloc(struct XenDevice *xendev)
+{
+ struct usbback_info *usbif;
+ USBPort *p;
+ unsigned int i, max_grants;
+
+ usbif = container_of(xendev, struct usbback_info, xendev);
+
+ usb_bus_new(&usbif->bus, sizeof(usbif->bus), &xen_usb_bus_ops, xen_sysdev);
+ for (i = 0; i < USBBACK_MAXPORTS; i++) {
+ p = &(usbif->ports[i].port);
+ usb_register_port(&usbif->bus, p, usbif, i, &xen_usb_port_ops,
+ USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL |
+ USB_SPEED_MASK_HIGH);
+ snprintf(p->path, sizeof(p->path), "%d", 99);
+ }
+
+ QTAILQ_INIT(&usbif->req_free_q);
+ QSIMPLEQ_INIT(&usbif->hotplug_q);
+ usbif->bh = qemu_bh_new(usbback_bh, usbif);
+
+ /* max_grants: for each request and for the rings (request and connect). */
+ max_grants = USBIF_MAX_SEGMENTS_PER_REQUEST * USB_URB_RING_SIZE + 2;
+ if (xengnttab_set_max_grants(xendev->gnttabdev, max_grants) < 0) {
+ xen_be_printf(xendev, 0, "xengnttab_set_max_grants failed: %s\n",
+ strerror(errno));
+ }
+}
+
+static int usbback_free(struct XenDevice *xendev)
+{
+ struct usbback_info *usbif;
+ struct usbback_req *usbback_req;
+ struct usbback_hotplug *usb_hp;
+ unsigned int i;
+
+ TR_BUS(xendev, "start\n");
+
+ usbback_disconnect(xendev);
+ usbif = container_of(xendev, struct usbback_info, xendev);
+ for (i = 1; i <= usbif->num_ports; i++) {
+ usbback_portid_remove(usbif, i);
+ }
+
+ while (!QTAILQ_EMPTY(&usbif->req_free_q)) {
+ usbback_req = QTAILQ_FIRST(&usbif->req_free_q);
+ QTAILQ_REMOVE(&usbif->req_free_q, usbback_req, q);
+ g_free(usbback_req);
+ }
+ while (!QSIMPLEQ_EMPTY(&usbif->hotplug_q)) {
+ usb_hp = QSIMPLEQ_FIRST(&usbif->hotplug_q);
+ QSIMPLEQ_REMOVE_HEAD(&usbif->hotplug_q, q);
+ g_free(usb_hp);
+ }
+
+ qemu_bh_delete(usbif->bh);
+
+ for (i = 0; i < USBBACK_MAXPORTS; i++) {
+ usb_unregister_port(&usbif->bus, &(usbif->ports[i].port));
+ }
+
+ usb_bus_release(&usbif->bus);
+
+ TR_BUS(xendev, "finished\n");
+
+ return 0;
+}
+
+static void usbback_event(struct XenDevice *xendev)
+{
+ struct usbback_info *usbif;
+
+ usbif = container_of(xendev, struct usbback_info, xendev);
+ qemu_bh_schedule(usbif->bh);
+}
+
+struct XenDevOps xen_usb_ops = {
+ .size = sizeof(struct usbback_info),
+ .flags = DEVOPS_FLAG_NEED_GNTDEV,
+ .init = usbback_init,
+ .alloc = usbback_alloc,
+ .free = usbback_free,
+ .backend_changed = usbback_backend_changed,
+ .initialise = usbback_connect,
+ .disconnect = usbback_disconnect,
+ .event = usbback_event,
+};
+
+#else /* USBIF_SHORT_NOT_OK */
+
+static int usbback_not_supported(void)
+{
+ return -EINVAL;
+}
+
+struct XenDevOps xen_usb_ops = {
+ .backend_register = usbback_not_supported,
+};
+
+#endif
diff --git a/hw/watchdog/watchdog.c b/hw/watchdog/watchdog.c
index bbf3646bae..2aeaf1fbc9 100644
--- a/hw/watchdog/watchdog.c
+++ b/hw/watchdog/watchdog.c
@@ -143,7 +143,7 @@ void watchdog_perform_action(void)
case WDT_NMI:
qapi_event_send_watchdog(WATCHDOG_EXPIRATION_ACTION_INJECT_NMI,
&error_abort);
- inject_nmi();
+ nmi_monitor_handle(0, NULL);
break;
}
}
diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c
index 60575ad38d..c63f9df38b 100644
--- a/hw/xen/xen_backend.c
+++ b/hw/xen/xen_backend.c
@@ -42,11 +42,36 @@ struct xs_handle *xenstore = NULL;
const char *xen_protocol;
/* private */
+struct xs_dirs {
+ char *xs_dir;
+ QTAILQ_ENTRY(xs_dirs) list;
+};
+static QTAILQ_HEAD(xs_dirs_head, xs_dirs) xs_cleanup =
+ QTAILQ_HEAD_INITIALIZER(xs_cleanup);
+
static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = QTAILQ_HEAD_INITIALIZER(xendevs);
static int debug = 0;
/* ------------------------------------------------------------- */
+static void xenstore_cleanup_dir(char *dir)
+{
+ struct xs_dirs *d;
+
+ d = g_malloc(sizeof(*d));
+ d->xs_dir = dir;
+ QTAILQ_INSERT_TAIL(&xs_cleanup, d, list);
+}
+
+void xen_config_cleanup(void)
+{
+ struct xs_dirs *d;
+
+ QTAILQ_FOREACH(d, &xs_cleanup, list) {
+ xs_rm(xenstore, 0, d->xs_dir);
+ }
+}
+
int xenstore_write_str(const char *base, const char *node, const char *val)
{
char abspath[XEN_BUFSIZE];
@@ -75,6 +100,30 @@ char *xenstore_read_str(const char *base, const char *node)
return ret;
}
+int xenstore_mkdir(char *path, int p)
+{
+ struct xs_permissions perms[2] = {
+ {
+ .id = 0, /* set owner: dom0 */
+ }, {
+ .id = xen_domid,
+ .perms = p,
+ }
+ };
+
+ if (!xs_mkdir(xenstore, 0, path)) {
+ xen_be_printf(NULL, 0, "xs_mkdir %s: failed\n", path);
+ return -1;
+ }
+ xenstore_cleanup_dir(g_strdup(path));
+
+ if (!xs_set_permissions(xenstore, 0, path, perms, 2)) {
+ xen_be_printf(NULL, 0, "xs_set_permissions %s: failed\n", path);
+ return -1;
+ }
+ return 0;
+}
+
int xenstore_write_int(const char *base, const char *node, int ival)
{
char val[12];
@@ -726,6 +775,20 @@ err:
int xen_be_register(const char *type, struct XenDevOps *ops)
{
+ char path[50];
+ int rc;
+
+ if (ops->backend_register) {
+ rc = ops->backend_register();
+ if (rc) {
+ return rc;
+ }
+ }
+
+ snprintf(path, sizeof(path), "device-model/%u/backends/%s", xen_domid,
+ type);
+ xenstore_mkdir(path, XS_PERM_NONE);
+
return xenstore_scan(type, xen_domid, ops);
}
diff --git a/hw/xen/xen_devconfig.c b/hw/xen/xen_devconfig.c
index 1f30fe4f5a..b7d290df6c 100644
--- a/hw/xen/xen_devconfig.c
+++ b/hw/xen/xen_devconfig.c
@@ -5,54 +5,6 @@
/* ------------------------------------------------------------- */
-struct xs_dirs {
- char *xs_dir;
- QTAILQ_ENTRY(xs_dirs) list;
-};
-static QTAILQ_HEAD(xs_dirs_head, xs_dirs) xs_cleanup = QTAILQ_HEAD_INITIALIZER(xs_cleanup);
-
-static void xen_config_cleanup_dir(char *dir)
-{
- struct xs_dirs *d;
-
- d = g_malloc(sizeof(*d));
- d->xs_dir = dir;
- QTAILQ_INSERT_TAIL(&xs_cleanup, d, list);
-}
-
-void xen_config_cleanup(void)
-{
- struct xs_dirs *d;
-
- QTAILQ_FOREACH(d, &xs_cleanup, list) {
- xs_rm(xenstore, 0, d->xs_dir);
- }
-}
-
-/* ------------------------------------------------------------- */
-
-static int xen_config_dev_mkdir(char *dev, int p)
-{
- struct xs_permissions perms[2] = {{
- .id = 0, /* set owner: dom0 */
- },{
- .id = xen_domid,
- .perms = p,
- }};
-
- if (!xs_mkdir(xenstore, 0, dev)) {
- xen_be_printf(NULL, 0, "xs_mkdir %s: failed\n", dev);
- return -1;
- }
- xen_config_cleanup_dir(g_strdup(dev));
-
- if (!xs_set_permissions(xenstore, 0, dev, perms, 2)) {
- xen_be_printf(NULL, 0, "xs_set_permissions %s: failed\n", dev);
- return -1;
- }
- return 0;
-}
-
static int xen_config_dev_dirs(const char *ftype, const char *btype, int vdev,
char *fe, char *be, int len)
{
@@ -66,8 +18,8 @@ static int xen_config_dev_dirs(const char *ftype, const char *btype, int vdev,
snprintf(be, len, "%s/backend/%s/%d/%d", dom, btype, xen_domid, vdev);
free(dom);
- xen_config_dev_mkdir(fe, XS_PERM_READ | XS_PERM_WRITE);
- xen_config_dev_mkdir(be, XS_PERM_READ);
+ xenstore_mkdir(fe, XS_PERM_READ | XS_PERM_WRITE);
+ xenstore_mkdir(be, XS_PERM_READ);
return 0;
}
diff --git a/hw/xenpv/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c
index fc13535992..f68cf48a29 100644
--- a/hw/xenpv/xen_machine_pv.c
+++ b/hw/xenpv/xen_machine_pv.c
@@ -25,10 +25,15 @@
#include "qemu/osdep.h"
#include "hw/hw.h"
#include "hw/boards.h"
+#include "hw/sysbus.h"
#include "hw/xen/xen_backend.h"
#include "xen_domainbuild.h"
#include "sysemu/block-backend.h"
+#define TYPE_XENSYSDEV "xensysdev"
+
+DeviceState *xen_sysdev;
+
static void xen_init_pv(MachineState *machine)
{
DriveInfo *dinfo;
@@ -67,11 +72,17 @@ static void xen_init_pv(MachineState *machine)
break;
}
+ xen_sysdev = qdev_create(NULL, TYPE_XENSYSDEV);
+ qdev_init_nofail(xen_sysdev);
+
xen_be_register("console", &xen_console_ops);
xen_be_register("vkbd", &xen_kbdmouse_ops);
xen_be_register("vfb", &xen_framebuffer_ops);
xen_be_register("qdisk", &xen_blkdev_ops);
xen_be_register("qnic", &xen_netdev_ops);
+#ifdef CONFIG_USB_LIBUSB
+ xen_be_register("qusb", &xen_usb_ops);
+#endif
/* configure framebuffer */
if (xenfb_enabled) {
@@ -101,6 +112,38 @@ static void xen_init_pv(MachineState *machine)
xen_init_display(xen_domid);
}
+static int xen_sysdev_init(SysBusDevice *dev)
+{
+ return 0;
+}
+
+static Property xen_sysdev_properties[] = {
+ {/* end of property list */},
+};
+
+static void xen_sysdev_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = xen_sysdev_init;
+ dc->props = xen_sysdev_properties;
+}
+
+static const TypeInfo xensysdev_info = {
+ .name = TYPE_XENSYSDEV,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SysBusDevice),
+ .class_init = xen_sysdev_class_init,
+};
+
+static void xenpv_register_types(void)
+{
+ type_register_static(&xensysdev_info);
+}
+
+type_init(xenpv_register_types);
+
static void xenpv_machine_init(MachineClass *mc)
{
mc->desc = "Xen Para-virtualized PC";
diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h
index 04eade5b7b..a2c3b92742 100644
--- a/include/exec/cpu-common.h
+++ b/include/exec/cpu-common.h
@@ -61,8 +61,8 @@ MemoryRegion *qemu_ram_addr_from_host(void *ptr, ram_addr_t *ram_addr);
RAMBlock *qemu_ram_block_by_name(const char *name);
RAMBlock *qemu_ram_block_from_host(void *ptr, bool round_offset,
ram_addr_t *ram_addr, ram_addr_t *offset);
-void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev);
-void qemu_ram_unset_idstr(ram_addr_t addr);
+void qemu_ram_set_idstr(RAMBlock *block, const char *name, DeviceState *dev);
+void qemu_ram_unset_idstr(RAMBlock *block);
const char *qemu_ram_get_idstr(RAMBlock *rb);
void cpu_physical_memory_rw(hwaddr addr, uint8_t *buf,
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 7fb9188c0a..f649697ee9 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -187,7 +187,6 @@ struct MemoryRegion {
MemoryRegion *alias;
hwaddr alias_offset;
int32_t priority;
- bool may_overlap;
QTAILQ_HEAD(subregions, MemoryRegion) subregions;
QTAILQ_ENTRY(MemoryRegion) subregions_link;
QTAILQ_HEAD(coalesced_ranges, CoalescedMemoryRange) coalesced;
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index 5adf7a4fcd..5b6e1b8b86 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -110,7 +110,7 @@ void qemu_set_ram_fd(ram_addr_t addr, int fd);
void *qemu_get_ram_block_host_ptr(ram_addr_t addr);
void qemu_ram_free(RAMBlock *block);
-int qemu_ram_resize(ram_addr_t base, ram_addr_t newsize, Error **errp);
+int qemu_ram_resize(RAMBlock *block, ram_addr_t newsize, Error **errp);
#define DIRTY_CLIENTS_ALL ((1 << DIRTY_MEMORY_NUM) - 1)
#define DIRTY_CLIENTS_NOCODE (DIRTY_CLIENTS_ALL & ~(1 << DIRTY_MEMORY_CODE))
diff --git a/include/hw/boards.h b/include/hw/boards.h
index 8d4fe56b5f..d268bd00a9 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -114,7 +114,7 @@ struct MachineClass {
const char *default_machine_opts;
const char *default_boot_order;
const char *default_display;
- GlobalProperty *compat_props;
+ GArray *compat_props;
const char *hw_version;
ram_addr_t default_ram_size;
bool option_rom_has_mr;
@@ -154,6 +154,7 @@ struct MachineState {
bool iommu;
bool suppress_vmdesc;
bool enforce_config_section;
+ bool enable_graphics;
ram_addr_t ram_size;
ram_addr_t maxram_size;
@@ -185,11 +186,18 @@ struct MachineState {
#define SET_MACHINE_COMPAT(m, COMPAT) \
do { \
+ int i; \
static GlobalProperty props[] = { \
COMPAT \
{ /* end of list */ } \
}; \
- (m)->compat_props = props; \
+ if (!m->compat_props) { \
+ m->compat_props = g_array_new(false, false, sizeof(void *)); \
+ } \
+ for (i = 0; props[i].driver != NULL; i++) { \
+ GlobalProperty *prop = &props[i]; \
+ g_array_append_val(m->compat_props, prop); \
+ } \
} while (0)
#endif
diff --git a/include/hw/i386/ioapic_internal.h b/include/hw/i386/ioapic_internal.h
index 797ed47305..cab9e67ee7 100644
--- a/include/hw/i386/ioapic_internal.h
+++ b/include/hw/i386/ioapic_internal.h
@@ -47,6 +47,11 @@
#define IOAPIC_LVT_DEST_MODE (1 << IOAPIC_LVT_DEST_MODE_SHIFT)
#define IOAPIC_LVT_DELIV_MODE (7 << IOAPIC_LVT_DELIV_MODE_SHIFT)
+/* Bits that are read-only for IOAPIC entry */
+#define IOAPIC_RO_BITS (IOAPIC_LVT_REMOTE_IRR | \
+ IOAPIC_LVT_DELIV_STATUS)
+#define IOAPIC_RW_BITS (~(uint64_t)IOAPIC_RO_BITS)
+
#define IOAPIC_TRIGGER_EDGE 0
#define IOAPIC_TRIGGER_LEVEL 1
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 96f0b66c77..367b6dbf0e 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -360,7 +360,6 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
HW_COMPAT_2_5
#define PC_COMPAT_2_4 \
- PC_COMPAT_2_5 \
HW_COMPAT_2_4 \
{\
.driver = "Haswell-" TYPE_X86_CPU,\
@@ -431,7 +430,6 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
#define PC_COMPAT_2_3 \
- PC_COMPAT_2_4 \
HW_COMPAT_2_3 \
{\
.driver = TYPE_X86_CPU,\
@@ -512,7 +510,6 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
},
#define PC_COMPAT_2_2 \
- PC_COMPAT_2_3 \
HW_COMPAT_2_2 \
{\
.driver = "kvm64" "-" TYPE_X86_CPU,\
@@ -606,7 +603,6 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
},
#define PC_COMPAT_2_1 \
- PC_COMPAT_2_2 \
HW_COMPAT_2_1 \
{\
.driver = "coreduo" "-" TYPE_X86_CPU,\
@@ -620,7 +616,6 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
},
#define PC_COMPAT_2_0 \
- PC_COMPAT_2_1 \
{\
.driver = "virtio-scsi-pci",\
.property = "any_layout",\
@@ -680,7 +675,6 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
},
#define PC_COMPAT_1_7 \
- PC_COMPAT_2_0 \
{\
.driver = TYPE_USB_DEVICE,\
.property = "msos-desc",\
@@ -698,7 +692,6 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
},
#define PC_COMPAT_1_6 \
- PC_COMPAT_1_7 \
{\
.driver = "e1000",\
.property = "mitigation",\
@@ -722,7 +715,6 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
},
#define PC_COMPAT_1_5 \
- PC_COMPAT_1_6 \
{\
.driver = "Conroe-" TYPE_X86_CPU,\
.property = "model",\
@@ -766,7 +758,6 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
},
#define PC_COMPAT_1_4 \
- PC_COMPAT_1_5 \
{\
.driver = "scsi-hd",\
.property = "discard_granularity",\
diff --git a/include/hw/mem/pc-dimm.h b/include/hw/mem/pc-dimm.h
index 218dfb0eda..8cdc3266b3 100644
--- a/include/hw/mem/pc-dimm.h
+++ b/include/hw/mem/pc-dimm.h
@@ -20,8 +20,6 @@
#include "sysemu/hostmem.h"
#include "hw/qdev.h"
-#define DEFAULT_PC_DIMMSIZE (1024*1024*1024)
-
#define TYPE_PC_DIMM "pc-dimm"
#define PC_DIMM(obj) \
OBJECT_CHECK(PCDIMMDevice, (obj), TYPE_PC_DIMM)
@@ -72,7 +70,7 @@ typedef struct PCDIMMDeviceClass {
/**
* MemoryHotplugState:
- * @base: address in guest RAM address space where hotplug memory
+ * @base: address in guest physical address space where hotplug memory
* address space begins.
* @mr: hotplug memory address space container
*/
diff --git a/include/hw/nmi.h b/include/hw/nmi.h
index f4cec6257d..b541772e1d 100644
--- a/include/hw/nmi.h
+++ b/include/hw/nmi.h
@@ -45,6 +45,5 @@ typedef struct NMIClass {
} NMIClass;
void nmi_monitor_handle(int cpu_index, Error **errp);
-void inject_nmi(void);
#endif /* NMI_H */
diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
index 13b0ab0848..1602a13ba2 100644
--- a/include/hw/virtio/virtio-gpu.h
+++ b/include/hw/virtio/virtio-gpu.h
@@ -27,8 +27,6 @@
#define VIRTIO_ID_GPU 16
-#define VIRTIO_GPU_MAX_SCANOUT 4
-
struct virtio_gpu_simple_resource {
uint32_t resource_id;
uint32_t width;
@@ -98,8 +96,8 @@ typedef struct VirtIOGPU {
QTAILQ_HEAD(, virtio_gpu_ctrl_command) cmdq;
QTAILQ_HEAD(, virtio_gpu_ctrl_command) fenceq;
- struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUT];
- struct virtio_gpu_requested_state req_state[VIRTIO_GPU_MAX_SCANOUT];
+ struct virtio_gpu_scanout scanout[VIRTIO_GPU_MAX_SCANOUTS];
+ struct virtio_gpu_requested_state req_state[VIRTIO_GPU_MAX_SCANOUTS];
struct virtio_gpu_conf conf;
int enabled_output_bitmask;
diff --git a/include/hw/virtio/virtio-rng.h b/include/hw/virtio/virtio-rng.h
index 3f07de70c7..2bc1ee5b50 100644
--- a/include/hw/virtio/virtio-rng.h
+++ b/include/hw/virtio/virtio-rng.h
@@ -26,7 +26,7 @@ struct VirtIORNGConf {
RngBackend *rng;
uint64_t max_bytes;
uint32_t period_ms;
- RndRandom *default_backend;
+ RngRandom *default_backend;
};
typedef struct VirtIORNG {
diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h
index c839eeb489..6e18a46a97 100644
--- a/include/hw/xen/xen_backend.h
+++ b/include/hw/xen/xen_backend.h
@@ -28,6 +28,7 @@ struct XenDevOps {
int (*free)(struct XenDevice *xendev);
void (*backend_changed)(struct XenDevice *xendev, const char *node);
void (*frontend_changed)(struct XenDevice *xendev, const char *node);
+ int (*backend_register)(void);
};
struct XenDevice {
@@ -60,8 +61,10 @@ extern xc_interface *xen_xc;
extern xenforeignmemory_handle *xen_fmem;
extern struct xs_handle *xenstore;
extern const char *xen_protocol;
+extern DeviceState *xen_sysdev;
/* xenstore helper functions */
+int xenstore_mkdir(char *path, int p);
int xenstore_write_str(const char *base, const char *node, const char *val);
int xenstore_write_int(const char *base, const char *node, int ival);
int xenstore_write_int64(const char *base, const char *node, int64_t ival);
@@ -98,6 +101,9 @@ extern struct XenDevOps xen_kbdmouse_ops; /* xen_framebuffer.c */
extern struct XenDevOps xen_framebuffer_ops; /* xen_framebuffer.c */
extern struct XenDevOps xen_blkdev_ops; /* xen_disk.c */
extern struct XenDevOps xen_netdev_ops; /* xen_nic.c */
+#ifdef CONFIG_USB_LIBUSB
+extern struct XenDevOps xen_usb_ops; /* xen-usb.c */
+#endif
void xen_init_display(int domid);
diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h
index 7b52e8ffc1..5eabf37328 100644
--- a/include/hw/xen/xen_common.h
+++ b/include/hw/xen/xen_common.h
@@ -49,6 +49,8 @@ typedef xc_gnttab xengnttab_handle;
#define xengnttab_unmap(h, a, n) xc_gnttab_munmap(h, a, n)
#define xengnttab_map_grant_refs(h, c, d, r, p) \
xc_gnttab_map_grant_refs(h, c, d, r, p)
+#define xengnttab_map_domain_grant_refs(h, c, d, r, p) \
+ xc_gnttab_map_domain_grant_refs(h, c, d, r, p)
#define xenforeignmemory_open(l, f) xen_xc
diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
index 268ec66958..994bfa023a 100644
--- a/include/qemu/osdep.h
+++ b/include/qemu/osdep.h
@@ -263,6 +263,19 @@ void qemu_anon_ram_free(void *ptr, size_t size);
#endif
+#if defined(__linux__) && \
+ (defined(__x86_64__) || defined(__arm__) || defined(__aarch64__))
+ /* Use 2 MiB alignment so transparent hugepages can be used by KVM.
+ Valgrind does not support alignments larger than 1 MiB,
+ therefore we need special code which handles running on Valgrind. */
+# define QEMU_VMALLOC_ALIGN (512 * 4096)
+#elif defined(__linux__) && defined(__s390x__)
+ /* Use 1 MiB (segment size) alignment so gmap can be used by KVM. */
+# define QEMU_VMALLOC_ALIGN (256 * 4096)
+#else
+# define QEMU_VMALLOC_ALIGN getpagesize()
+#endif
+
int qemu_madvise(void *addr, size_t len, int advice);
int qemu_open(const char *name, int flags, ...);
diff --git a/include/sysemu/rng-random.h b/include/sysemu/rng-random.h
index 4332772a24..38186fe83d 100644
--- a/include/sysemu/rng-random.h
+++ b/include/sysemu/rng-random.h
@@ -15,8 +15,8 @@
#include "qom/object.h"
#define TYPE_RNG_RANDOM "rng-random"
-#define RNG_RANDOM(obj) OBJECT_CHECK(RndRandom, (obj), TYPE_RNG_RANDOM)
+#define RNG_RANDOM(obj) OBJECT_CHECK(RngRandom, (obj), TYPE_RNG_RANDOM)
-typedef struct RndRandom RndRandom;
+typedef struct RngRandom RngRandom;
#endif
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 38fb3cad35..618169c4d5 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -131,21 +131,12 @@ void qemu_savevm_send_postcopy_ram_discard(QEMUFile *f, const char *name,
int qemu_loadvm_state(QEMUFile *f);
-typedef enum DisplayType
-{
- DT_DEFAULT,
- DT_CURSES,
- DT_SDL,
- DT_GTK,
- DT_NOGRAPHIC,
- DT_NONE,
-} DisplayType;
-
extern int autostart;
typedef enum {
VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB, VGA_QXL,
VGA_TCX, VGA_CG3, VGA_DEVICE, VGA_VIRTIO,
+ VGA_TYPE_MAX,
} VGAInterfaceType;
extern int vga_interface_type;
@@ -154,7 +145,6 @@ extern int vga_interface_type;
extern int graphic_width;
extern int graphic_height;
extern int graphic_depth;
-extern DisplayType display_type;
extern int display_opengl;
extern const char *keyboard_layout;
extern int win2k_install_hack;
diff --git a/include/ui/console.h b/include/ui/console.h
index d5a88d93e8..52a5f65673 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -6,6 +6,8 @@
#include "qapi/qmp/qdict.h"
#include "qemu/notify.h"
#include "qapi-types.h"
+#include "qemu/error-report.h"
+#include "qapi/error.h"
#ifdef CONFIG_OPENGL
# include <epoxy/gl.h>
@@ -420,20 +422,45 @@ void surface_gl_setup_viewport(ConsoleGLState *gls,
#endif
/* sdl.c */
+#ifdef CONFIG_SDL
void sdl_display_early_init(int opengl);
void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
+#else
+static inline void sdl_display_early_init(int opengl)
+{
+ /* This must never be called if CONFIG_SDL is disabled */
+ error_report("SDL support is disabled");
+ abort();
+}
+static inline void sdl_display_init(DisplayState *ds, int full_screen,
+ int no_frame)
+{
+ /* This must never be called if CONFIG_SDL is disabled */
+ error_report("SDL support is disabled");
+ abort();
+}
+#endif
/* cocoa.m */
+#ifdef CONFIG_COCOA
void cocoa_display_init(DisplayState *ds, int full_screen);
+#else
+static inline void cocoa_display_init(DisplayState *ds, int full_screen)
+{
+ /* This must never be called if CONFIG_COCOA is disabled */
+ error_report("Cocoa support is disabled");
+ abort();
+}
+#endif
/* vnc.c */
void vnc_display_init(const char *id);
void vnc_display_open(const char *id, Error **errp);
void vnc_display_add_client(const char *id, int csock, bool skipauth);
-char *vnc_display_local_addr(const char *id);
#ifdef CONFIG_VNC
int vnc_display_password(const char *id, const char *password);
int vnc_display_pw_expire(const char *id, time_t expires);
+char *vnc_display_local_addr(const char *id);
QemuOpts *vnc_parse(const char *str, Error **errp);
int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp);
#else
@@ -445,16 +472,58 @@ static inline int vnc_display_pw_expire(const char *id, time_t expires)
{
return -ENODEV;
};
+static inline QemuOpts *vnc_parse(const char *str, Error **errp)
+{
+ error_setg(errp, "VNC support is disabled");
+ return NULL;
+}
+static inline int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)
+{
+ error_setg(errp, "VNC support is disabled");
+ return -1;
+}
+static inline char *vnc_display_local_addr(const char *id)
+{
+ /* This must never be called if CONFIG_VNC is disabled */
+ error_report("VNC support is disabled");
+ abort();
+}
#endif
/* curses.c */
+#ifdef CONFIG_CURSES
void curses_display_init(DisplayState *ds, int full_screen);
+#else
+static inline void curses_display_init(DisplayState *ds, int full_screen)
+{
+ /* This must never be called if CONFIG_CURSES is disabled */
+ error_report("curses support is disabled");
+ abort();
+}
+#endif
/* input.c */
int index_from_key(const char *key, size_t key_length);
/* gtk.c */
+#ifdef CONFIG_GTK
void early_gtk_display_init(int opengl);
void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover);
+#else
+static inline void gtk_display_init(DisplayState *ds, bool full_screen,
+ bool grab_on_hover)
+{
+ /* This must never be called if CONFIG_GTK is disabled */
+ error_report("GTK support is disabled");
+ abort();
+}
+
+static inline void early_gtk_display_init(int opengl)
+{
+ /* This must never be called if CONFIG_GTK is disabled */
+ error_report("GTK support is disabled");
+ abort();
+}
+#endif
#endif
diff --git a/include/ui/qemu-spice.h b/include/ui/qemu-spice.h
index aa2436355f..57ac91b921 100644
--- a/include/ui/qemu-spice.h
+++ b/include/ui/qemu-spice.h
@@ -51,6 +51,8 @@ static inline CharDriverState *qemu_chr_open_spice_port(const char *name)
#else /* CONFIG_SPICE */
+#include "qemu/error-report.h"
+
#define using_spice 0
#define spice_displays 0
static inline int qemu_spice_set_passwd(const char *passwd,
@@ -75,6 +77,17 @@ static inline int qemu_spice_display_add_client(int csock, int skipauth,
return -1;
}
+static inline void qemu_spice_display_init(void)
+{
+ /* This must never be called if CONFIG_SPICE is disabled */
+ error_report("spice support is disabled");
+ abort();
+}
+
+static inline void qemu_spice_init(void)
+{
+}
+
#endif /* CONFIG_SPICE */
static inline bool qemu_using_spice(Error **errp)
diff --git a/memory.c b/memory.c
index a8ef85261f..4e3cda8a12 100644
--- a/memory.c
+++ b/memory.c
@@ -227,7 +227,6 @@ struct FlatRange {
hwaddr offset_in_region;
AddrRange addr;
uint8_t dirty_log_mask;
- bool romd_mode;
bool readonly;
};
@@ -252,7 +251,6 @@ static bool flatrange_equal(FlatRange *a, FlatRange *b)
return a->mr == b->mr
&& addrrange_equal(a->addr, b->addr)
&& a->offset_in_region == b->offset_in_region
- && a->romd_mode == b->romd_mode
&& a->readonly == b->readonly;
}
@@ -312,7 +310,6 @@ static bool can_merge(FlatRange *r1, FlatRange *r2)
r1->addr.size),
int128_make64(r2->offset_in_region))
&& r1->dirty_log_mask == r2->dirty_log_mask
- && r1->romd_mode == r2->romd_mode
&& r1->readonly == r2->readonly;
}
@@ -666,7 +663,6 @@ static void render_memory_region(FlatView *view,
fr.mr = mr;
fr.dirty_log_mask = memory_region_get_dirty_log_mask(mr);
- fr.romd_mode = mr->romd_mode;
fr.readonly = readonly;
/* Render the region itself into any gaps left by the current view. */
@@ -1057,13 +1053,6 @@ static void memory_region_get_priority(Object *obj, Visitor *v,
visit_type_int32(v, name, &value, errp);
}
-static bool memory_region_get_may_overlap(Object *obj, Error **errp)
-{
- MemoryRegion *mr = MEMORY_REGION(obj);
-
- return mr->may_overlap;
-}
-
static void memory_region_get_size(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
@@ -1101,10 +1090,6 @@ static void memory_region_initfn(Object *obj)
memory_region_get_priority,
NULL, /* memory_region_set_priority */
NULL, NULL, &error_abort);
- object_property_add_bool(OBJECT(mr), "may-overlap",
- memory_region_get_may_overlap,
- NULL, /* memory_region_set_may_overlap */
- &error_abort);
object_property_add(OBJECT(mr), "size", "uint64",
memory_region_get_size,
NULL, /* memory_region_set_size, */
@@ -1643,7 +1628,7 @@ int memory_region_get_fd(MemoryRegion *mr)
assert(mr->ram_block);
- return qemu_get_ram_fd(memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK);
+ return qemu_get_ram_fd(memory_region_get_ram_addr(mr));
}
void *memory_region_get_ram_ptr(MemoryRegion *mr)
@@ -1657,8 +1642,7 @@ void *memory_region_get_ram_ptr(MemoryRegion *mr)
mr = mr->alias;
}
assert(mr->ram_block);
- ptr = qemu_get_ram_ptr(mr->ram_block,
- memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK);
+ ptr = qemu_get_ram_ptr(mr->ram_block, memory_region_get_ram_addr(mr));
rcu_read_unlock();
return ptr + offset;
@@ -1673,7 +1657,7 @@ void memory_region_ram_resize(MemoryRegion *mr, ram_addr_t newsize, Error **errp
{
assert(mr->ram_block);
- qemu_ram_resize(memory_region_get_ram_addr(mr), newsize, errp);
+ qemu_ram_resize(mr->ram_block, newsize, errp);
}
static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpace *as)
@@ -1864,7 +1848,6 @@ void memory_region_del_eventfd(MemoryRegion *mr,
static void memory_region_update_container_subregions(MemoryRegion *subregion)
{
- hwaddr offset = subregion->addr;
MemoryRegion *mr = subregion->container;
MemoryRegion *other;
@@ -1872,27 +1855,6 @@ static void memory_region_update_container_subregions(MemoryRegion *subregion)
memory_region_ref(subregion);
QTAILQ_FOREACH(other, &mr->subregions, subregions_link) {
- if (subregion->may_overlap || other->may_overlap) {
- continue;
- }
- if (int128_ge(int128_make64(offset),
- int128_add(int128_make64(other->addr), other->size))
- || int128_le(int128_add(int128_make64(offset), subregion->size),
- int128_make64(other->addr))) {
- continue;
- }
-#if 0
- printf("warning: subregion collision %llx/%llx (%s) "
- "vs %llx/%llx (%s)\n",
- (unsigned long long)offset,
- (unsigned long long)int128_get64(subregion->size),
- subregion->name,
- (unsigned long long)other->addr,
- (unsigned long long)int128_get64(other->size),
- other->name);
-#endif
- }
- QTAILQ_FOREACH(other, &mr->subregions, subregions_link) {
if (subregion->priority >= other->priority) {
QTAILQ_INSERT_BEFORE(other, subregion, subregions_link);
goto done;
@@ -1918,7 +1880,6 @@ void memory_region_add_subregion(MemoryRegion *mr,
hwaddr offset,
MemoryRegion *subregion)
{
- subregion->may_overlap = false;
subregion->priority = 0;
memory_region_add_subregion_common(mr, offset, subregion);
}
@@ -1928,7 +1889,6 @@ void memory_region_add_subregion_overlap(MemoryRegion *mr,
MemoryRegion *subregion,
int priority)
{
- subregion->may_overlap = true;
subregion->priority = priority;
memory_region_add_subregion_common(mr, offset, subregion);
}
diff --git a/migration/ram.c b/migration/ram.c
index d1ecb99961..54e215128c 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -2478,7 +2478,7 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
if (length != block->used_length) {
Error *local_err = NULL;
- ret = qemu_ram_resize(block->offset, length,
+ ret = qemu_ram_resize(block, length,
&local_err);
if (local_err) {
error_report_err(local_err);
diff --git a/migration/savevm.c b/migration/savevm.c
index f8450fd0e9..65ce0c61a3 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -2229,13 +2229,13 @@ void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
void vmstate_register_ram(MemoryRegion *mr, DeviceState *dev)
{
- qemu_ram_set_idstr(memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK,
+ qemu_ram_set_idstr(mr->ram_block,
memory_region_name(mr), dev);
}
void vmstate_unregister_ram(MemoryRegion *mr, DeviceState *dev)
{
- qemu_ram_unset_idstr(memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK);
+ qemu_ram_unset_idstr(mr->ram_block);
}
void vmstate_register_ram_global(MemoryRegion *mr)
diff --git a/qemu-img.c b/qemu-img.c
index 47923663be..7ed8ef21cb 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -3492,10 +3492,7 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE);
}
- if (qcrypto_init(&local_error) < 0) {
- error_reportf_err(local_error, "cannot initialize crypto: ");
- exit(1);
- }
+ qcrypto_init(&error_fatal);
module_call_init(MODULE_INIT_QOM);
bdrv_init();
diff --git a/qemu-io.c b/qemu-io.c
index 5ef3ef7f35..d977a6e553 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -466,10 +466,7 @@ int main(int argc, char **argv)
progname = basename(argv[0]);
qemu_init_exec_dir(argv[0]);
- if (qcrypto_init(&local_error) < 0) {
- error_reportf_err(local_error, "cannot initialize crypto: ");
- exit(1);
- }
+ qcrypto_init(&error_fatal);
module_call_init(MODULE_INIT_QOM);
qemu_add_opts(&qemu_object_opts);
diff --git a/qemu-nbd.c b/qemu-nbd.c
index d59b187780..6554f0ab65 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -527,10 +527,7 @@ int main(int argc, char **argv)
sa_sigterm.sa_handler = termsig_handler;
sigaction(SIGTERM, &sa_sigterm, NULL);
- if (qcrypto_init(&local_err) < 0) {
- error_reportf_err(local_err, "cannot initialize crypto: ");
- exit(1);
- }
+ qcrypto_init(&error_fatal);
module_call_init(MODULE_INIT_QOM);
qemu_add_opts(&qemu_object_opts);
diff --git a/scripts/cocci-macro-file.h b/scripts/cocci-macro-file.h
index eceb4be73f..9f2e72e7e1 100644
--- a/scripts/cocci-macro-file.h
+++ b/scripts/cocci-macro-file.h
@@ -117,3 +117,9 @@ struct { \
type *tqe_next; /* next element */ \
type **tqe_prev; /* address of previous next element */ \
}
+
+/* From glib */
+#define g_assert_cmpint(a, op, b) g_assert(a op b)
+#define g_assert_cmpuint(a, op, b) g_assert(a op b)
+#define g_assert_cmphex(a, op, b) g_assert(a op b)
+#define g_assert_cmpstr(a, op, b) g_assert(strcmp(a, b) op 0)
diff --git a/scripts/signrom.py b/scripts/signrom.py
index f9c35ccfca..5629bca222 100644
--- a/scripts/signrom.py
+++ b/scripts/signrom.py
@@ -17,11 +17,33 @@ if len(sys.argv) < 3:
fin = open(sys.argv[1], 'rb')
fout = open(sys.argv[2], 'wb')
-fin.seek(2)
-size = ord(fin.read(1)) * 512 - 1
+magic = fin.read(2)
+if magic != '\x55\xaa':
+ sys.exit("%s: option ROM does not begin with magic 55 aa" % sys.argv[1])
+size_byte = ord(fin.read(1))
fin.seek(0)
-data = fin.read(size)
+
+if size_byte == 0:
+ # If the caller left the size field blank then we will fill it in,
+ # also rounding the whole input to a multiple of 512 bytes.
+ data = fin.read()
+ # +1 because we need a byte to store the checksum.
+ size = len(data) + 1
+ # Round up to next multiple of 512.
+ size += 511
+ size -= size % 512
+ if size >= 65536:
+ sys.exit("%s: option ROM size too large" % sys.argv[1])
+ # size-1 because a final byte is added below to store the checksum.
+ data = data.ljust(size-1, '\0')
+ data = data[:2] + chr(size/512) + data[3:]
+else:
+ # Otherwise the input file specifies the size so use it.
+ # -1 because we overwrite the last byte of the file with the checksum.
+ size = size_byte * 512 - 1
+ data = fin.read(size)
+
fout.write(data)
checksum = 0
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 8085467945..731b10de06 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -8008,6 +8008,11 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
}
/* fallthru */
case 0xf9 ... 0xff: /* sfence */
+ if (!(s->cpuid_features & CPUID_SSE)
+ || (prefixes & PREFIX_LOCK)) {
+ goto illegal_op;
+ }
+ break;
case 0xe8 ... 0xef: /* lfence */
case 0xf0 ... 0xf7: /* mfence */
if (!(s->cpuid_features & CPUID_SSE2)
diff --git a/translate-all.c b/translate-all.c
index 1c1c85530a..c599dc4d41 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -1555,8 +1555,7 @@ void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr)
rcu_read_unlock();
return;
}
- ram_addr = (memory_region_get_ram_addr(mr) & TARGET_PAGE_MASK)
- + addr;
+ ram_addr = memory_region_get_ram_addr(mr) + addr;
tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
rcu_read_unlock();
}
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
index 6cc4b8f001..4adde93ac1 100644
--- a/util/oslib-posix.c
+++ b/util/oslib-posix.c
@@ -26,19 +26,6 @@
* THE SOFTWARE.
*/
-#if defined(__linux__) && \
- (defined(__x86_64__) || defined(__arm__) || defined(__aarch64__))
- /* Use 2 MiB alignment so transparent hugepages can be used by KVM.
- Valgrind does not support alignments larger than 1 MiB,
- therefore we need special code which handles running on Valgrind. */
-# define QEMU_VMALLOC_ALIGN (512 * 4096)
-#elif defined(__linux__) && defined(__s390x__)
- /* Use 1 MiB (segment size) alignment so gmap can be used by KVM. */
-# define QEMU_VMALLOC_ALIGN (256 * 4096)
-#else
-# define QEMU_VMALLOC_ALIGN getpagesize()
-#endif
-
#include "qemu/osdep.h"
#include <termios.h>
#include <termios.h>
diff --git a/vl.c b/vl.c
index a43a3bad18..2569dbb8d8 100644
--- a/vl.c
+++ b/vl.c
@@ -129,10 +129,8 @@ static const char *data_dir[16];
static int data_dir_idx;
const char *bios_name = NULL;
enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
-DisplayType display_type = DT_DEFAULT;
int request_opengl = -1;
int display_opengl;
-static int display_remote;
const char* keyboard_layout = NULL;
ram_addr_t ram_size;
const char *mem_path = NULL;
@@ -148,9 +146,7 @@ int vga_interface_type = VGA_NONE;
static int full_screen = 0;
static int no_frame = 0;
int no_quit = 0;
-#ifdef CONFIG_GTK
static bool grab_on_hover;
-#endif
CharDriverState *serial_hds[MAX_SERIAL_PORTS];
CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
@@ -694,6 +690,10 @@ void runstate_set(RunState new_state)
{
assert(new_state < RUN_STATE__MAX);
+ if (current_run_state == new_state) {
+ return;
+ }
+
if (!runstate_valid_transitions[current_run_state][new_state]) {
error_report("invalid runstate transition: '%s' -> '%s'",
RunState_lookup[current_run_state],
@@ -892,16 +892,13 @@ static void configure_rtc(QemuOpts *opts)
value = qemu_opt_get(opts, "driftfix");
if (value) {
if (!strcmp(value, "slew")) {
- static GlobalProperty slew_lost_ticks[] = {
- {
- .driver = "mc146818rtc",
- .property = "lost_tick_policy",
- .value = "slew",
- },
- { /* end of list */ }
+ static GlobalProperty slew_lost_ticks = {
+ .driver = "mc146818rtc",
+ .property = "lost_tick_policy",
+ .value = "slew",
};
- qdev_prop_register_global_list(slew_lost_ticks);
+ qdev_prop_register_global(&slew_lost_ticks);
} else if (!strcmp(value, "none")) {
/* discard is default */
} else {
@@ -1981,99 +1978,86 @@ static const QEMUOption qemu_options[] = {
{ NULL },
};
-static bool vga_available(void)
-{
- return object_class_by_name("VGA") || object_class_by_name("isa-vga");
-}
-
-static bool cirrus_vga_available(void)
-{
- return object_class_by_name("cirrus-vga")
- || object_class_by_name("isa-cirrus-vga");
-}
-
-static bool vmware_vga_available(void)
-{
- return object_class_by_name("vmware-svga");
-}
-
-static bool qxl_vga_available(void)
-{
- return object_class_by_name("qxl-vga");
-}
-
-static bool tcx_vga_available(void)
-{
- return object_class_by_name("SUNW,tcx");
-}
+typedef struct VGAInterfaceInfo {
+ const char *opt_name; /* option name */
+ const char *name; /* human-readable name */
+ /* Class names indicating that support is available.
+ * If no class is specified, the interface is always available */
+ const char *class_names[2];
+} VGAInterfaceInfo;
+
+static VGAInterfaceInfo vga_interfaces[VGA_TYPE_MAX] = {
+ [VGA_NONE] = {
+ .opt_name = "none",
+ },
+ [VGA_STD] = {
+ .opt_name = "std",
+ .name = "standard VGA",
+ .class_names = { "VGA", "isa-vga" },
+ },
+ [VGA_CIRRUS] = {
+ .opt_name = "cirrus",
+ .name = "Cirrus VGA",
+ .class_names = { "cirrus-vga", "isa-cirrus-vga" },
+ },
+ [VGA_VMWARE] = {
+ .opt_name = "vmware",
+ .name = "VMWare SVGA",
+ .class_names = { "vmware-svga" },
+ },
+ [VGA_VIRTIO] = {
+ .opt_name = "virtio",
+ .name = "Virtio VGA",
+ .class_names = { "virtio-vga" },
+ },
+ [VGA_QXL] = {
+ .opt_name = "qxl",
+ .name = "QXL VGA",
+ .class_names = { "qxl-vga" },
+ },
+ [VGA_TCX] = {
+ .opt_name = "tcx",
+ .name = "TCX framebuffer",
+ .class_names = { "SUNW,tcx" },
+ },
+ [VGA_CG3] = {
+ .opt_name = "cg3",
+ .name = "CG3 framebuffer",
+ .class_names = { "cgthree" },
+ },
+ [VGA_XENFB] = {
+ .opt_name = "xenfb",
+ },
+};
-static bool cg3_vga_available(void)
+static bool vga_interface_available(VGAInterfaceType t)
{
- return object_class_by_name("cgthree");
-}
+ VGAInterfaceInfo *ti = &vga_interfaces[t];
-static bool virtio_vga_available(void)
-{
- return object_class_by_name("virtio-vga");
+ assert(t < VGA_TYPE_MAX);
+ return !ti->class_names[0] ||
+ object_class_by_name(ti->class_names[0]) ||
+ object_class_by_name(ti->class_names[1]);
}
-static void select_vgahw (const char *p)
+static void select_vgahw(const char *p)
{
const char *opts;
+ int t;
assert(vga_interface_type == VGA_NONE);
- if (strstart(p, "std", &opts)) {
- if (vga_available()) {
- vga_interface_type = VGA_STD;
- } else {
- error_report("standard VGA not available");
- exit(0);
- }
- } else if (strstart(p, "cirrus", &opts)) {
- if (cirrus_vga_available()) {
- vga_interface_type = VGA_CIRRUS;
- } else {
- error_report("Cirrus VGA not available");
- exit(0);
- }
- } else if (strstart(p, "vmware", &opts)) {
- if (vmware_vga_available()) {
- vga_interface_type = VGA_VMWARE;
- } else {
- error_report("VMWare SVGA not available");
- exit(0);
- }
- } else if (strstart(p, "virtio", &opts)) {
- if (virtio_vga_available()) {
- vga_interface_type = VGA_VIRTIO;
- } else {
- error_report("Virtio VGA not available");
- exit(0);
- }
- } else if (strstart(p, "xenfb", &opts)) {
- vga_interface_type = VGA_XENFB;
- } else if (strstart(p, "qxl", &opts)) {
- if (qxl_vga_available()) {
- vga_interface_type = VGA_QXL;
- } else {
- error_report("QXL VGA not available");
- exit(0);
- }
- } else if (strstart(p, "tcx", &opts)) {
- if (tcx_vga_available()) {
- vga_interface_type = VGA_TCX;
- } else {
- error_report("TCX framebuffer not available");
- exit(0);
- }
- } else if (strstart(p, "cg3", &opts)) {
- if (cg3_vga_available()) {
- vga_interface_type = VGA_CG3;
- } else {
- error_report("CG3 framebuffer not available");
- exit(0);
+ for (t = 0; t < VGA_TYPE_MAX; t++) {
+ VGAInterfaceInfo *ti = &vga_interfaces[t];
+ if (ti->opt_name && strstart(p, ti->opt_name, &opts)) {
+ if (!vga_interface_available(t)) {
+ error_report("%s not available", ti->name);
+ exit(1);
+ }
+ vga_interface_type = t;
+ break;
}
- } else if (!strstart(p, "none", &opts)) {
+ }
+ if (t == VGA_TYPE_MAX) {
invalid_vga:
error_report("unknown vga type: %s", p);
exit(1);
@@ -2093,6 +2077,15 @@ static void select_vgahw (const char *p)
}
}
+typedef enum DisplayType {
+ DT_DEFAULT,
+ DT_CURSES,
+ DT_SDL,
+ DT_COCOA,
+ DT_GTK,
+ DT_NONE,
+} DisplayType;
+
static DisplayType select_display(const char *p)
{
const char *opts;
@@ -2161,21 +2154,12 @@ static DisplayType select_display(const char *p)
exit(1);
#endif
} else if (strstart(p, "vnc", &opts)) {
-#ifdef CONFIG_VNC
if (*opts == '=') {
- Error *err = NULL;
- if (vnc_parse(opts + 1, &err) == NULL) {
- error_report_err(err);
- exit(1);
- }
+ vnc_parse(opts + 1, &error_fatal);
} else {
error_report("VNC requires a display argument vnc=<display>");
exit(1);
}
-#else
- error_report("VNC support is disabled");
- exit(1);
-#endif
} else if (strstart(p, "curses", &opts)) {
#ifdef CONFIG_CURSES
display = DT_CURSES;
@@ -2424,7 +2408,6 @@ static int mon_init_func(void *opaque, QemuOpts *opts, Error **errp)
static void monitor_parse(const char *optarg, const char *mode, bool pretty)
{
static int monitor_device_index = 0;
- Error *local_err = NULL;
QemuOpts *opts;
const char *p;
char label[32];
@@ -2445,11 +2428,7 @@ static void monitor_parse(const char *optarg, const char *mode, bool pretty)
}
}
- opts = qemu_opts_create(qemu_find_opts("mon"), label, 1, &local_err);
- if (!opts) {
- error_report_err(local_err);
- exit(1);
- }
+ opts = qemu_opts_create(qemu_find_opts("mon"), label, 1, &error_fatal);
qemu_opt_set(opts, "mode", mode, &error_abort);
qemu_opt_set(opts, "chardev", label, &error_abort);
qemu_opt_set_bool(opts, "pretty", pretty, &error_abort);
@@ -2979,11 +2958,12 @@ int main(int argc, char **argv, char **envp)
const char *qtest_log = NULL;
const char *pid_file = NULL;
const char *incoming = NULL;
-#ifdef CONFIG_VNC
int show_vnc_port = 0;
-#endif
bool defconfig = true;
bool userconfig = true;
+ bool nographic = false;
+ DisplayType display_type = DT_DEFAULT;
+ int display_remote = 0;
const char *log_mask = NULL;
const char *log_file = NULL;
char *trace_file = NULL;
@@ -3228,7 +3208,10 @@ int main(int argc, char **argv, char **envp)
display_type = select_display(optarg);
break;
case QEMU_OPTION_nographic:
- display_type = DT_NOGRAPHIC;
+ olist = qemu_find_opts("machine");
+ qemu_opts_parse_noisily(olist, "graphics=off", false);
+ nographic = true;
+ display_type = DT_NONE;
break;
case QEMU_OPTION_curses:
#ifdef CONFIG_CURSES
@@ -3635,16 +3618,13 @@ int main(int argc, char **argv, char **envp)
win2k_install_hack = 1;
break;
case QEMU_OPTION_rtc_td_hack: {
- static GlobalProperty slew_lost_ticks[] = {
- {
- .driver = "mc146818rtc",
- .property = "lost_tick_policy",
- .value = "slew",
- },
- { /* end of list */ }
+ static GlobalProperty slew_lost_ticks = {
+ .driver = "mc146818rtc",
+ .property = "lost_tick_policy",
+ .value = "slew",
};
- qdev_prop_register_global_list(slew_lost_ticks);
+ qdev_prop_register_global(&slew_lost_ticks);
break;
}
case QEMU_OPTION_acpitable:
@@ -3691,18 +3671,15 @@ int main(int argc, char **argv, char **envp)
break;
}
case QEMU_OPTION_no_kvm_pit_reinjection: {
- static GlobalProperty kvm_pit_lost_tick_policy[] = {
- {
- .driver = "kvm-pit",
- .property = "lost_tick_policy",
- .value = "discard",
- },
- { /* end of list */ }
+ static GlobalProperty kvm_pit_lost_tick_policy = {
+ .driver = "kvm-pit",
+ .property = "lost_tick_policy",
+ .value = "discard",
};
error_report("warning: deprecated, replaced by "
"-global kvm-pit.lost_tick_policy=discard");
- qdev_prop_register_global_list(kvm_pit_lost_tick_policy);
+ qdev_prop_register_global(&kvm_pit_lost_tick_policy);
break;
}
case QEMU_OPTION_usb:
@@ -3727,20 +3704,8 @@ int main(int argc, char **argv, char **envp)
}
break;
case QEMU_OPTION_vnc:
- {
-#ifdef CONFIG_VNC
- Error *local_err = NULL;
-
- if (vnc_parse(optarg, &local_err) == NULL) {
- error_report_err(local_err);
- exit(1);
- }
-#else
- error_report("VNC support is disabled");
- exit(1);
-#endif
+ vnc_parse(optarg, &error_fatal);
break;
- }
case QEMU_OPTION_no_acpi:
acpi_enabled = 0;
break;
@@ -4194,7 +4159,7 @@ int main(int argc, char **argv, char **envp)
* -nographic _and_ redirects all ports explicitly - this is valid
* usage, -nographic is just a no-op in this case.
*/
- if (display_type == DT_NOGRAPHIC
+ if (nographic
&& (default_parallel || default_serial
|| default_monitor || default_virtcon)) {
error_report("-nographic cannot be used with -daemonize");
@@ -4208,7 +4173,7 @@ int main(int argc, char **argv, char **envp)
#endif
}
- if (display_type == DT_NOGRAPHIC) {
+ if (nographic) {
if (default_parallel)
add_device_config(DEV_PARALLEL, "null");
if (default_serial && default_monitor) {
@@ -4250,8 +4215,10 @@ int main(int argc, char **argv, char **envp)
if (display_type == DT_DEFAULT && !display_remote) {
#if defined(CONFIG_GTK)
display_type = DT_GTK;
-#elif defined(CONFIG_SDL) || defined(CONFIG_COCOA)
+#elif defined(CONFIG_SDL)
display_type = DT_SDL;
+#elif defined(CONFIG_COCOA)
+ display_type = DT_COCOA;
#elif defined(CONFIG_VNC)
vnc_parse("localhost:0,to=99,id=default", &error_abort);
show_vnc_port = 1;
@@ -4269,16 +4236,14 @@ int main(int argc, char **argv, char **envp)
"ignoring option");
}
-#if defined(CONFIG_GTK)
if (display_type == DT_GTK) {
early_gtk_display_init(request_opengl);
}
-#endif
-#if defined(CONFIG_SDL)
+
if (display_type == DT_SDL) {
sdl_display_early_init(request_opengl);
}
-#endif
+
if (request_opengl == 1 && display_opengl == 0) {
#if defined(CONFIG_OPENGL)
error_report("OpenGL is not supported by the display");
@@ -4387,10 +4352,8 @@ int main(int argc, char **argv, char **envp)
os_set_line_buffering();
-#ifdef CONFIG_SPICE
/* spice needs the timers to be initialized by this point */
qemu_spice_init();
-#endif
cpu_ticks_init();
if (icount_opts) {
@@ -4481,9 +4444,9 @@ int main(int argc, char **argv, char **envp)
if (default_vga) {
if (machine_class->default_display) {
vga_model = machine_class->default_display;
- } else if (cirrus_vga_available()) {
+ } else if (vga_interface_available(VGA_CIRRUS)) {
vga_model = "cirrus";
- } else if (vga_available()) {
+ } else if (vga_interface_available(VGA_STD)) {
vga_model = "std";
}
}
@@ -4498,7 +4461,11 @@ int main(int argc, char **argv, char **envp)
}
if (machine_class->compat_props) {
- qdev_prop_register_global_list(machine_class->compat_props);
+ GlobalProperty *p;
+ for (i = 0; i < machine_class->compat_props->len; i++) {
+ p = g_array_index(machine_class->compat_props, GlobalProperty *, i);
+ qdev_prop_register_global(p);
+ }
}
qemu_add_globals();
@@ -4560,28 +4527,18 @@ int main(int argc, char **argv, char **envp)
/* init local displays */
switch (display_type) {
- case DT_NOGRAPHIC:
- (void)ds; /* avoid warning if no display is configured */
- break;
-#if defined(CONFIG_CURSES)
case DT_CURSES:
curses_display_init(ds, full_screen);
break;
-#endif
-#if defined(CONFIG_SDL)
case DT_SDL:
sdl_display_init(ds, full_screen, no_frame);
break;
-#elif defined(CONFIG_COCOA)
- case DT_SDL:
+ case DT_COCOA:
cocoa_display_init(ds, full_screen);
break;
-#endif
-#if defined(CONFIG_GTK)
case DT_GTK:
gtk_display_init(ds, full_screen, grab_on_hover);
break;
-#endif
default:
break;
}
@@ -4589,7 +4546,6 @@ int main(int argc, char **argv, char **envp)
/* must be after terminal init, SDL library changes signal handlers */
os_setup_signal_handling();
-#ifdef CONFIG_VNC
/* init remote displays */
qemu_opts_foreach(qemu_find_opts("vnc"),
vnc_init_func, NULL, NULL);
@@ -4598,12 +4554,10 @@ int main(int argc, char **argv, char **envp)
printf("VNC server running on '%s'\n", ret);
g_free(ret);
}
-#endif
-#ifdef CONFIG_SPICE
+
if (using_spice) {
qemu_spice_display_init();
}
-#endif
if (foreach_device_config(DEV_GDB, gdbserver_start) < 0) {
exit(1);