diff options
63 files changed, 1716 insertions, 524 deletions
@@ -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 @@ -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"\ @@ -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. @@ -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) @@ -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(); @@ -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> @@ -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); |