diff options
Diffstat (limited to 'hw')
| -rw-r--r-- | hw/acpi/cpu_hotplug.c | 2 | ||||
| -rw-r--r-- | hw/acpi/ich9.c | 2 | ||||
| -rw-r--r-- | hw/acpi/piix4.c | 2 | ||||
| -rw-r--r-- | hw/arm/smmu-common.c | 2 | ||||
| -rw-r--r-- | hw/arm/virt-acpi-build.c | 2 | ||||
| -rw-r--r-- | hw/core/Makefile.objs | 1 | ||||
| -rw-r--r-- | hw/core/cpu.c | 458 | ||||
| -rw-r--r-- | hw/core/generic-loader.c | 2 | ||||
| -rw-r--r-- | hw/core/machine-qmp-cmds.c | 10 | ||||
| -rw-r--r-- | hw/core/null-machine.c | 2 | ||||
| -rw-r--r-- | hw/core/numa.c | 2 | ||||
| -rw-r--r-- | hw/cpu/a9mpcore.c | 2 | ||||
| -rw-r--r-- | hw/cpu/cluster.c | 2 | ||||
| -rw-r--r-- | hw/display/ati.c | 112 | ||||
| -rw-r--r-- | hw/display/ati_dbg.c | 10 | ||||
| -rw-r--r-- | hw/display/ati_int.h | 5 | ||||
| -rw-r--r-- | hw/display/ati_regs.h | 17 | ||||
| -rw-r--r-- | hw/i386/acpi-build.c | 2 | ||||
| -rw-r--r-- | hw/i386/pc.c | 2 | ||||
| -rw-r--r-- | hw/intc/arm_gic.c | 2 | ||||
| -rw-r--r-- | hw/intc/arm_gicv3_common.c | 2 | ||||
| -rw-r--r-- | hw/isa/lpc_ich9.c | 2 | ||||
| -rw-r--r-- | hw/misc/imx6_src.c | 2 | ||||
| -rw-r--r-- | hw/ppc/spapr.c | 2 | ||||
| -rw-r--r-- | hw/timer/a9gtimer.c | 2 | ||||
| -rw-r--r-- | hw/timer/arm_mptimer.c | 2 | ||||
| -rw-r--r-- | hw/usb/hcd-ehci.c | 3 | ||||
| -rw-r--r-- | hw/usb/hcd-xhci.c | 3 | ||||
| -rw-r--r-- | hw/usb/redirect.c | 74 |
29 files changed, 673 insertions, 58 deletions
diff --git a/hw/acpi/cpu_hotplug.c b/hw/acpi/cpu_hotplug.c index a83567e6aa..6e8293aac9 100644 --- a/hw/acpi/cpu_hotplug.c +++ b/hw/acpi/cpu_hotplug.c @@ -12,7 +12,7 @@ #include "qemu/osdep.h" #include "hw/acpi/cpu_hotplug.h" #include "qapi/error.h" -#include "qom/cpu.h" +#include "hw/core/cpu.h" #include "hw/i386/pc.h" #include "qemu/error-report.h" diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c index 2ca52bf045..2034dd749e 100644 --- a/hw/acpi/ich9.c +++ b/hw/acpi/ich9.c @@ -31,7 +31,7 @@ #include "hw/pci/pci.h" #include "migration/vmstate.h" #include "qemu/timer.h" -#include "qom/cpu.h" +#include "hw/core/cpu.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" #include "hw/acpi/acpi.h" diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 1c907d2a7d..5742c3df87 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -44,7 +44,7 @@ #include "hw/xen/xen.h" #include "migration/qemu-file-types.h" #include "migration/vmstate.h" -#include "qom/cpu.h" +#include "hw/core/cpu.h" #include "trace.h" #define GPE_BASE 0xafe0 diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index 956ebe32c8..245817d23e 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -20,7 +20,7 @@ #include "exec/address-spaces.h" #include "trace.h" #include "exec/target_page.h" -#include "qom/cpu.h" +#include "hw/core/cpu.h" #include "hw/qdev-properties.h" #include "qapi/error.h" #include "qemu/jhash.h" diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index fa9afd2b7e..a8b2d97fe9 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -30,7 +30,7 @@ #include "qapi/error.h" #include "qemu/bitmap.h" #include "trace.h" -#include "qom/cpu.h" +#include "hw/core/cpu.h" #include "target/arm/cpu.h" #include "hw/acpi/acpi-defs.h" #include "hw/acpi/acpi.h" diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs index b49f880a0c..fd0550d1d9 100644 --- a/hw/core/Makefile.objs +++ b/hw/core/Makefile.objs @@ -8,6 +8,7 @@ common-obj-y += irq.o common-obj-y += hotplug.o common-obj-$(CONFIG_SOFTMMU) += nmi.o common-obj-$(CONFIG_SOFTMMU) += vm-change-state-handler.o +common-obj-y += cpu.o common-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o common-obj-$(CONFIG_XILINX_AXI) += stream.o diff --git a/hw/core/cpu.c b/hw/core/cpu.c new file mode 100644 index 0000000000..0035845511 --- /dev/null +++ b/hw/core/cpu.c @@ -0,0 +1,458 @@ +/* + * QEMU CPU model + * + * Copyright (c) 2012-2014 SUSE LINUX Products GmbH + * + * 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; either version 2 + * of the License, or (at your option) any later version. + * + * 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/gpl-2.0.html> + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/core/cpu.h" +#include "sysemu/hw_accel.h" +#include "qemu/notify.h" +#include "qemu/log.h" +#include "qemu/main-loop.h" +#include "exec/log.h" +#include "qemu/error-report.h" +#include "qemu/qemu-print.h" +#include "sysemu/tcg.h" +#include "hw/boards.h" +#include "hw/qdev-properties.h" +#include "trace-root.h" + +CPUInterruptHandler cpu_interrupt_handler; + +CPUState *cpu_by_arch_id(int64_t id) +{ + CPUState *cpu; + + CPU_FOREACH(cpu) { + CPUClass *cc = CPU_GET_CLASS(cpu); + + if (cc->get_arch_id(cpu) == id) { + return cpu; + } + } + return NULL; +} + +bool cpu_exists(int64_t id) +{ + return !!cpu_by_arch_id(id); +} + +CPUState *cpu_create(const char *typename) +{ + Error *err = NULL; + CPUState *cpu = CPU(object_new(typename)); + object_property_set_bool(OBJECT(cpu), true, "realized", &err); + if (err != NULL) { + error_report_err(err); + object_unref(OBJECT(cpu)); + exit(EXIT_FAILURE); + } + return cpu; +} + +bool cpu_paging_enabled(const CPUState *cpu) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + return cc->get_paging_enabled(cpu); +} + +static bool cpu_common_get_paging_enabled(const CPUState *cpu) +{ + return false; +} + +void cpu_get_memory_mapping(CPUState *cpu, MemoryMappingList *list, + Error **errp) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + cc->get_memory_mapping(cpu, list, errp); +} + +static void cpu_common_get_memory_mapping(CPUState *cpu, + MemoryMappingList *list, + Error **errp) +{ + error_setg(errp, "Obtaining memory mappings is unsupported on this CPU."); +} + +/* Resetting the IRQ comes from across the code base so we take the + * BQL here if we need to. cpu_interrupt assumes it is held.*/ +void cpu_reset_interrupt(CPUState *cpu, int mask) +{ + bool need_lock = !qemu_mutex_iothread_locked(); + + if (need_lock) { + qemu_mutex_lock_iothread(); + } + cpu->interrupt_request &= ~mask; + if (need_lock) { + qemu_mutex_unlock_iothread(); + } +} + +void cpu_exit(CPUState *cpu) +{ + atomic_set(&cpu->exit_request, 1); + /* Ensure cpu_exec will see the exit request after TCG has exited. */ + smp_wmb(); + atomic_set(&cpu->icount_decr_ptr->u16.high, -1); +} + +int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu, + void *opaque) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + return (*cc->write_elf32_qemunote)(f, cpu, opaque); +} + +static int cpu_common_write_elf32_qemunote(WriteCoreDumpFunction f, + CPUState *cpu, void *opaque) +{ + return 0; +} + +int cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cpu, + int cpuid, void *opaque) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + return (*cc->write_elf32_note)(f, cpu, cpuid, opaque); +} + +static int cpu_common_write_elf32_note(WriteCoreDumpFunction f, + CPUState *cpu, int cpuid, + void *opaque) +{ + return -1; +} + +int cpu_write_elf64_qemunote(WriteCoreDumpFunction f, CPUState *cpu, + void *opaque) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + return (*cc->write_elf64_qemunote)(f, cpu, opaque); +} + +static int cpu_common_write_elf64_qemunote(WriteCoreDumpFunction f, + CPUState *cpu, void *opaque) +{ + return 0; +} + +int cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cpu, + int cpuid, void *opaque) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + return (*cc->write_elf64_note)(f, cpu, cpuid, opaque); +} + +static int cpu_common_write_elf64_note(WriteCoreDumpFunction f, + CPUState *cpu, int cpuid, + void *opaque) +{ + return -1; +} + + +static int cpu_common_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg) +{ + return 0; +} + +static int cpu_common_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg) +{ + return 0; +} + +static bool cpu_common_debug_check_watchpoint(CPUState *cpu, CPUWatchpoint *wp) +{ + /* If no extra check is required, QEMU watchpoint match can be considered + * as an architectural match. + */ + return true; +} + +static bool cpu_common_virtio_is_big_endian(CPUState *cpu) +{ + return target_words_bigendian(); +} + +static void cpu_common_noop(CPUState *cpu) +{ +} + +static bool cpu_common_exec_interrupt(CPUState *cpu, int int_req) +{ + return false; +} + +GuestPanicInformation *cpu_get_crash_info(CPUState *cpu) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + GuestPanicInformation *res = NULL; + + if (cc->get_crash_info) { + res = cc->get_crash_info(cpu); + } + return res; +} + +void cpu_dump_state(CPUState *cpu, FILE *f, int flags) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + if (cc->dump_state) { + cpu_synchronize_state(cpu); + cc->dump_state(cpu, f, flags); + } +} + +void cpu_dump_statistics(CPUState *cpu, int flags) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + if (cc->dump_statistics) { + cc->dump_statistics(cpu, flags); + } +} + +void cpu_reset(CPUState *cpu) +{ + CPUClass *klass = CPU_GET_CLASS(cpu); + + if (klass->reset != NULL) { + (*klass->reset)(cpu); + } + + trace_guest_cpu_reset(cpu); +} + +static void cpu_common_reset(CPUState *cpu) +{ + CPUClass *cc = CPU_GET_CLASS(cpu); + + if (qemu_loglevel_mask(CPU_LOG_RESET)) { + qemu_log("CPU Reset (CPU %d)\n", cpu->cpu_index); + log_cpu_state(cpu, cc->reset_dump_flags); + } + + cpu->interrupt_request = 0; + cpu->halted = 0; + cpu->mem_io_pc = 0; + cpu->mem_io_vaddr = 0; + cpu->icount_extra = 0; + atomic_set(&cpu->icount_decr_ptr->u32, 0); + cpu->can_do_io = 1; + cpu->exception_index = -1; + cpu->crash_occurred = false; + cpu->cflags_next_tb = -1; + + if (tcg_enabled()) { + cpu_tb_jmp_cache_clear(cpu); + + tcg_flush_softmmu_tlb(cpu); + } +} + +static bool cpu_common_has_work(CPUState *cs) +{ + return false; +} + +ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model) +{ + CPUClass *cc = CPU_CLASS(object_class_by_name(typename)); + + assert(cpu_model && cc->class_by_name); + return cc->class_by_name(cpu_model); +} + +static void cpu_common_parse_features(const char *typename, char *features, + Error **errp) +{ + char *val; + static bool cpu_globals_initialized; + /* Single "key=value" string being parsed */ + char *featurestr = features ? strtok(features, ",") : NULL; + + /* should be called only once, catch invalid users */ + assert(!cpu_globals_initialized); + cpu_globals_initialized = true; + + while (featurestr) { + val = strchr(featurestr, '='); + if (val) { + GlobalProperty *prop = g_new0(typeof(*prop), 1); + *val = 0; + val++; + prop->driver = typename; + prop->property = g_strdup(featurestr); + prop->value = g_strdup(val); + qdev_prop_register_global(prop); + } else { + error_setg(errp, "Expected key=value format, found %s.", + featurestr); + return; + } + featurestr = strtok(NULL, ","); + } +} + +static void cpu_common_realizefn(DeviceState *dev, Error **errp) +{ + CPUState *cpu = CPU(dev); + Object *machine = qdev_get_machine(); + + /* qdev_get_machine() can return something that's not TYPE_MACHINE + * if this is one of the user-only emulators; in that case there's + * no need to check the ignore_memory_transaction_failures board flag. + */ + if (object_dynamic_cast(machine, TYPE_MACHINE)) { + ObjectClass *oc = object_get_class(machine); + MachineClass *mc = MACHINE_CLASS(oc); + + if (mc) { + cpu->ignore_memory_transaction_failures = + mc->ignore_memory_transaction_failures; + } + } + + if (dev->hotplugged) { + cpu_synchronize_post_init(cpu); + cpu_resume(cpu); + } + + /* NOTE: latest generic point where the cpu is fully realized */ + trace_init_vcpu(cpu); +} + +static void cpu_common_unrealizefn(DeviceState *dev, Error **errp) +{ + CPUState *cpu = CPU(dev); + /* NOTE: latest generic point before the cpu is fully unrealized */ + trace_fini_vcpu(cpu); + cpu_exec_unrealizefn(cpu); +} + +static void cpu_common_initfn(Object *obj) +{ + CPUState *cpu = CPU(obj); + CPUClass *cc = CPU_GET_CLASS(obj); + + cpu->cpu_index = UNASSIGNED_CPU_INDEX; + cpu->cluster_index = UNASSIGNED_CLUSTER_INDEX; + cpu->gdb_num_regs = cpu->gdb_num_g_regs = cc->gdb_num_core_regs; + /* *-user doesn't have configurable SMP topology */ + /* the default value is changed by qemu_init_vcpu() for softmmu */ + cpu->nr_cores = 1; + cpu->nr_threads = 1; + + qemu_mutex_init(&cpu->work_mutex); + QTAILQ_INIT(&cpu->breakpoints); + QTAILQ_INIT(&cpu->watchpoints); + + cpu_exec_initfn(cpu); +} + +static void cpu_common_finalize(Object *obj) +{ + CPUState *cpu = CPU(obj); + + qemu_mutex_destroy(&cpu->work_mutex); +} + +static int64_t cpu_common_get_arch_id(CPUState *cpu) +{ + return cpu->cpu_index; +} + +static vaddr cpu_adjust_watchpoint_address(CPUState *cpu, vaddr addr, int len) +{ + return addr; +} + +static void generic_handle_interrupt(CPUState *cpu, int mask) +{ + cpu->interrupt_request |= mask; + + if (!qemu_cpu_is_self(cpu)) { + qemu_cpu_kick(cpu); + } +} + +CPUInterruptHandler cpu_interrupt_handler = generic_handle_interrupt; + +static void cpu_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + CPUClass *k = CPU_CLASS(klass); + + k->parse_features = cpu_common_parse_features; + k->reset = cpu_common_reset; + k->get_arch_id = cpu_common_get_arch_id; + k->has_work = cpu_common_has_work; + k->get_paging_enabled = cpu_common_get_paging_enabled; + k->get_memory_mapping = cpu_common_get_memory_mapping; + k->write_elf32_qemunote = cpu_common_write_elf32_qemunote; + k->write_elf32_note = cpu_common_write_elf32_note; + k->write_elf64_qemunote = cpu_common_write_elf64_qemunote; + k->write_elf64_note = cpu_common_write_elf64_note; + k->gdb_read_register = cpu_common_gdb_read_register; + k->gdb_write_register = cpu_common_gdb_write_register; + k->virtio_is_big_endian = cpu_common_virtio_is_big_endian; + k->debug_excp_handler = cpu_common_noop; + k->debug_check_watchpoint = cpu_common_debug_check_watchpoint; + k->cpu_exec_enter = cpu_common_noop; + k->cpu_exec_exit = cpu_common_noop; + k->cpu_exec_interrupt = cpu_common_exec_interrupt; + k->adjust_watchpoint_address = cpu_adjust_watchpoint_address; + set_bit(DEVICE_CATEGORY_CPU, dc->categories); + dc->realize = cpu_common_realizefn; + dc->unrealize = cpu_common_unrealizefn; + dc->props = cpu_common_props; + /* + * Reason: CPUs still need special care by board code: wiring up + * IRQs, adding reset handlers, halting non-first CPUs, ... + */ + dc->user_creatable = false; +} + +static const TypeInfo cpu_type_info = { + .name = TYPE_CPU, + .parent = TYPE_DEVICE, + .instance_size = sizeof(CPUState), + .instance_init = cpu_common_initfn, + .instance_finalize = cpu_common_finalize, + .abstract = true, + .class_size = sizeof(CPUClass), + .class_init = cpu_class_init, +}; + +static void cpu_register_types(void) +{ + type_register_static(&cpu_type_info); +} + +type_init(cpu_register_types) diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c index 06d8d6466e..4b1fc86a06 100644 --- a/hw/core/generic-loader.c +++ b/hw/core/generic-loader.c @@ -31,7 +31,7 @@ */ #include "qemu/osdep.h" -#include "qom/cpu.h" +#include "hw/core/cpu.h" #include "hw/sysbus.h" #include "sysemu/dma.h" #include "sysemu/reset.h" diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c index 526fbd5ced..15cf7c62e3 100644 --- a/hw/core/machine-qmp-cmds.c +++ b/hw/core/machine-qmp-cmds.c @@ -249,6 +249,16 @@ CurrentMachineParams *qmp_query_current_machine(Error **errp) return params; } +TargetInfo *qmp_query_target(Error **errp) +{ + TargetInfo *info = g_malloc0(sizeof(*info)); + + info->arch = qapi_enum_parse(&SysEmuTarget_lookup, TARGET_NAME, -1, + &error_abort); + + return info; +} + HotpluggableCPUList *qmp_query_hotpluggable_cpus(Error **errp) { MachineState *ms = MACHINE(qdev_get_machine()); diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c index 30b1991b52..1aa0a9a01a 100644 --- a/hw/core/null-machine.c +++ b/hw/core/null-machine.c @@ -16,7 +16,7 @@ #include "hw/boards.h" #include "sysemu/sysemu.h" #include "exec/address-spaces.h" -#include "qom/cpu.h" +#include "hw/core/cpu.h" static void machine_none_init(MachineState *mch) { diff --git a/hw/core/numa.c b/hw/core/numa.c index 7a63ddc4c6..4f7e4628a0 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -34,7 +34,7 @@ #include "qapi/opts-visitor.h" #include "qapi/qapi-visit-machine.h" #include "sysemu/qtest.h" -#include "qom/cpu.h" +#include "hw/core/cpu.h" #include "hw/mem/pc-dimm.h" #include "migration/vmstate.h" #include "hw/boards.h" diff --git a/hw/cpu/a9mpcore.c b/hw/cpu/a9mpcore.c index cd1e165faf..6872a3a00a 100644 --- a/hw/cpu/a9mpcore.c +++ b/hw/cpu/a9mpcore.c @@ -14,7 +14,7 @@ #include "hw/cpu/a9mpcore.h" #include "hw/irq.h" #include "hw/qdev-properties.h" -#include "qom/cpu.h" +#include "hw/core/cpu.h" static void a9mp_priv_set_irq(void *opaque, int irq, int level) { diff --git a/hw/cpu/cluster.c b/hw/cpu/cluster.c index 74d8d43c00..349a883261 100644 --- a/hw/cpu/cluster.c +++ b/hw/cpu/cluster.c @@ -21,7 +21,7 @@ #include "qemu/osdep.h" #include "hw/cpu/cluster.h" #include "hw/qdev-properties.h" -#include "qom/cpu.h" +#include "hw/core/cpu.h" #include "qapi/error.h" #include "qemu/module.h" #include "qemu/cutils.h" diff --git a/hw/display/ati.c b/hw/display/ati.c index 35f49a591b..8f940eee22 100644 --- a/hw/display/ati.c +++ b/hw/display/ati.c @@ -50,6 +50,7 @@ static void ati_vga_switch_mode(ATIVGAState *s) s->mode = EXT_MODE; if (s->regs.crtc_gen_cntl & CRTC2_EN) { /* CRT controller enabled, use CRTC values */ + /* FIXME Should these be the same as VGA CRTC regs? */ uint32_t offs = s->regs.crtc_offset & 0x07ffffff; int stride = (s->regs.crtc_pitch & 0x7ff) * 8; int bpp = 0; @@ -89,7 +90,9 @@ static void ati_vga_switch_mode(ATIVGAState *s) DPRINTF("Switching to %dx%d %d %d @ %x\n", h, v, stride, bpp, offs); vbe_ioport_write_index(&s->vga, 0, VBE_DISPI_INDEX_ENABLE); vbe_ioport_write_data(&s->vga, 0, VBE_DISPI_DISABLED); - s->vga.big_endian_fb = false; + s->vga.big_endian_fb = (s->regs.config_cntl & APER_0_ENDIAN || + s->regs.config_cntl & APER_1_ENDIAN ? + true : false); /* reset VBE regs then set up mode */ s->vga.vbe_regs[VBE_DISPI_INDEX_XRES] = h; s->vga.vbe_regs[VBE_DISPI_INDEX_YRES] = v; @@ -101,16 +104,23 @@ static void ati_vga_switch_mode(ATIVGAState *s) (s->regs.dac_cntl & DAC_8BIT_EN ? VBE_DISPI_8BIT_DAC : 0)); /* now set offset and stride after enable as that resets these */ if (stride) { + int bypp = DIV_ROUND_UP(bpp, BITS_PER_BYTE); + vbe_ioport_write_index(&s->vga, 0, VBE_DISPI_INDEX_VIRT_WIDTH); vbe_ioport_write_data(&s->vga, 0, stride); - if (offs % stride == 0) { - vbe_ioport_write_index(&s->vga, 0, VBE_DISPI_INDEX_Y_OFFSET); - vbe_ioport_write_data(&s->vga, 0, offs / stride); - } else { - /* FIXME what to do with this? */ - error_report("VGA offset is not multiple of pitch, " - "expect bad picture"); + stride *= bypp; + if (offs % stride) { + DPRINTF("CRTC offset is not multiple of pitch\n"); + vbe_ioport_write_index(&s->vga, 0, + VBE_DISPI_INDEX_X_OFFSET); + vbe_ioport_write_data(&s->vga, 0, offs % stride / bypp); } + vbe_ioport_write_index(&s->vga, 0, VBE_DISPI_INDEX_Y_OFFSET); + vbe_ioport_write_data(&s->vga, 0, offs / stride); + DPRINTF("VBE offset (%d,%d), vbe_start_addr=%x\n", + s->vga.vbe_regs[VBE_DISPI_INDEX_X_OFFSET], + s->vga.vbe_regs[VBE_DISPI_INDEX_Y_OFFSET], + s->vga.vbe_start_addr); } } } else { @@ -132,9 +142,8 @@ static void ati_cursor_define(ATIVGAState *s) return; /* Do not update cursor if locked or rendered by guest */ } /* FIXME handle cur_hv_offs correctly */ - src = s->vga.vram_ptr + (s->regs.crtc_offset & 0x07ffffff) + - s->regs.cur_offset - (s->regs.cur_hv_offs >> 16) - - (s->regs.cur_hv_offs & 0xffff) * 16; + src = s->vga.vram_ptr + s->regs.cur_offset - + (s->regs.cur_hv_offs >> 16) - (s->regs.cur_hv_offs & 0xffff) * 16; for (i = 0; i < 64; i++) { for (j = 0; j < 8; j++, idx++) { data[idx] = src[i * 16 + j]; @@ -190,8 +199,7 @@ static void ati_cursor_draw_line(VGACommonState *vga, uint8_t *d, int scr_y) return; } /* FIXME handle cur_hv_offs correctly */ - src = s->vga.vram_ptr + (s->regs.crtc_offset & 0x07ffffff) + - s->cursor_offset + (scr_y - vga->hw_cursor_y) * 16; + src = s->vga.vram_ptr + s->cursor_offset + (scr_y - vga->hw_cursor_y) * 16; dp = &dp[vga->hw_cursor_x]; h = ((s->regs.crtc_h_total_disp >> 16) + 1) * 8; for (i = 0; i < 8; i++) { @@ -207,7 +215,7 @@ static void ati_cursor_draw_line(VGACommonState *vga, uint8_t *d, int scr_y) } } else { color = (xbits & BIT(7) ? s->regs.cur_color1 : - s->regs.cur_color0) << 8 | 0xff; + s->regs.cur_color0) | 0xff000000; } if (vga->hw_cursor_x + i * 8 + j >= h) { return; /* end of screen, don't span to next line */ @@ -235,6 +243,21 @@ static uint64_t ati_i2c(bitbang_i2c_interface *i2c, uint64_t data, int base) return data; } +static void ati_vga_update_irq(ATIVGAState *s) +{ + pci_set_irq(&s->dev, !!(s->regs.gen_int_status & s->regs.gen_int_cntl)); +} + +static void ati_vga_vblank_irq(void *opaque) +{ + ATIVGAState *s = opaque; + + timer_mod(&s->vblank_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + + NANOSECONDS_PER_SECOND / 60); + s->regs.gen_int_status |= CRTC_VBLANK_INT; + ati_vga_update_irq(s); +} + static inline uint64_t ati_reg_read_offs(uint32_t reg, int offs, unsigned int size) { @@ -275,6 +298,12 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size) addr - (BIOS_0_SCRATCH + i * 4), size); break; } + case GEN_INT_CNTL: + val = s->regs.gen_int_cntl; + break; + case GEN_INT_STATUS: + val = s->regs.gen_int_status; + break; case CRTC_GEN_CNTL ... CRTC_GEN_CNTL + 3: val = ati_reg_read_offs(s->regs.crtc_gen_cntl, addr - CRTC_GEN_CNTL, size); @@ -304,9 +333,27 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size) case PALETTE_DATA: val = vga_ioport_read(&s->vga, VGA_PEL_D); break; + case CNFG_CNTL: + val = s->regs.config_cntl; + break; case CNFG_MEMSIZE: val = s->vga.vram_size; break; + case CONFIG_APER_0_BASE: + case CONFIG_APER_1_BASE: + val = pci_default_read_config(&s->dev, + PCI_BASE_ADDRESS_0, size) & 0xfffffff0; + break; + case CONFIG_APER_SIZE: + val = s->vga.vram_size; + break; + case CONFIG_REG_1_BASE: + val = pci_default_read_config(&s->dev, + PCI_BASE_ADDRESS_2, size) & 0xfffffff0; + break; + case CONFIG_REG_APER_SIZE: + val = memory_region_size(&s->mm); + break; case MC_STATUS: val = 5; break; @@ -486,6 +533,21 @@ static void ati_mm_write(void *opaque, hwaddr addr, addr - (BIOS_0_SCRATCH + i * 4), data, size); break; } + case GEN_INT_CNTL: + s->regs.gen_int_cntl = data; + if (data & CRTC_VBLANK_INT) { + ati_vga_vblank_irq(s); + } else { + timer_del(&s->vblank_timer); + ati_vga_update_irq(s); + } + break; + case GEN_INT_STATUS: + data &= (s->dev_id == PCI_DEVICE_ID_ATI_RAGE128_PF ? + 0x000f040fUL : 0xfc080effUL); + s->regs.gen_int_status &= ~data; + ati_vga_update_irq(s); + break; case CRTC_GEN_CNTL ... CRTC_GEN_CNTL + 3: { uint32_t val = s->regs.crtc_gen_cntl; @@ -549,12 +611,15 @@ static void ati_mm_write(void *opaque, hwaddr addr, addr - GPIO_MONID, data, size); /* * Rage128p accesses DDC used to get EDID via these bits. - * Only touch i2c when write overlaps 3rd byte because some - * drivers access this reg via multiple partial writes and - * without this spurious bits would be sent. + * Because some drivers access this via multiple byte writes + * we have to be careful when we send bits to avoid spurious + * changes in bitbang_i2c state. So only do it when mask is set + * and either the enable bits are changed or output bits changed + * while enabled. */ if ((s->regs.gpio_monid & BIT(25)) && - addr <= GPIO_MONID + 2 && addr + size > GPIO_MONID + 2) { + ((addr <= GPIO_MONID + 2 && addr + size > GPIO_MONID + 2) || + (addr == GPIO_MONID && (s->regs.gpio_monid & 0x60000)))) { s->regs.gpio_monid = ati_i2c(&s->bbi2c, s->regs.gpio_monid, 1); } } @@ -580,6 +645,9 @@ static void ati_mm_write(void *opaque, hwaddr addr, data >>= 8; vga_ioport_write(&s->vga, VGA_PEL_D, data & 0xff); break; + case CNFG_CNTL: + s->regs.config_cntl = data; + break; case CRTC_H_TOTAL_DISP: s->regs.crtc_h_total_disp = data & 0x07ff07ff; break; @@ -870,12 +938,19 @@ static void ati_vga_realize(PCIDevice *dev, Error **errp) pci_register_bar(dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &vga->vram); pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->io); pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mm); + + /* most interrupts are not yet emulated but MacOS needs at least VBlank */ + dev->config[PCI_INTERRUPT_PIN] = 1; + timer_init_ns(&s->vblank_timer, QEMU_CLOCK_VIRTUAL, ati_vga_vblank_irq, s); } static void ati_vga_reset(DeviceState *dev) { ATIVGAState *s = ATI_VGA(dev); + timer_del(&s->vblank_timer); + ati_vga_update_irq(s); + /* reset vga */ vga_common_reset(&s->vga); s->mode = VGA_MODE; @@ -885,6 +960,7 @@ static void ati_vga_exit(PCIDevice *dev) { ATIVGAState *s = ATI_VGA(dev); + timer_del(&s->vblank_timer); graphic_console_close(s->vga.con); } diff --git a/hw/display/ati_dbg.c b/hw/display/ati_dbg.c index 88b3a11315..0ebbd36f14 100644 --- a/hw/display/ati_dbg.c +++ b/hw/display/ati_dbg.c @@ -16,6 +16,7 @@ static struct ati_regdesc ati_reg_names[] = { {"BUS_CNTL", 0x0030}, {"BUS_CNTL1", 0x0034}, {"GEN_INT_CNTL", 0x0040}, + {"GEN_INT_STATUS", 0x0044}, {"CRTC_GEN_CNTL", 0x0050}, {"CRTC_EXT_CNTL", 0x0054}, {"DAC_CNTL", 0x0058}, @@ -23,11 +24,20 @@ static struct ati_regdesc ati_reg_names[] = { {"GPIO_DVI_DDC", 0x0064}, {"GPIO_MONID", 0x0068}, {"I2C_CNTL_1", 0x0094}, + {"AMCGPIO_MASK_MIR", 0x009c}, + {"AMCGPIO_A_MIR", 0x00a0}, + {"AMCGPIO_Y_MIR", 0x00a4}, + {"AMCGPIO_EN_MIR", 0x00a8}, {"PALETTE_INDEX", 0x00b0}, {"PALETTE_DATA", 0x00b4}, {"CNFG_CNTL", 0x00e0}, {"GEN_RESET_CNTL", 0x00f0}, {"CNFG_MEMSIZE", 0x00f8}, + {"CONFIG_APER_0_BASE", 0x0100}, + {"CONFIG_APER_1_BASE", 0x0104}, + {"CONFIG_APER_SIZE", 0x0108}, + {"CONFIG_REG_1_BASE", 0x010c}, + {"CONFIG_REG_APER_SIZE", 0x0110}, {"MEM_CNTL", 0x0140}, {"MC_FB_LOCATION", 0x0148}, {"MC_AGP_LOCATION", 0x014C}, diff --git a/hw/display/ati_int.h b/hw/display/ati_int.h index 31a1927b3e..2a16708e4f 100644 --- a/hw/display/ati_int.h +++ b/hw/display/ati_int.h @@ -9,6 +9,7 @@ #ifndef ATI_INT_H #define ATI_INT_H +#include "qemu/timer.h" #include "hw/pci/pci.h" #include "hw/i2c/bitbang_i2c.h" #include "vga_int.h" @@ -33,12 +34,15 @@ typedef struct ATIVGARegs { uint32_t mm_index; uint32_t bios_scratch[8]; + uint32_t gen_int_cntl; + uint32_t gen_int_status; uint32_t crtc_gen_cntl; uint32_t crtc_ext_cntl; uint32_t dac_cntl; uint32_t gpio_vga_ddc; uint32_t gpio_dvi_ddc; uint32_t gpio_monid; + uint32_t config_cntl; uint32_t crtc_h_total_disp; uint32_t crtc_h_sync_strt_wid; uint32_t crtc_v_total_disp; @@ -88,6 +92,7 @@ typedef struct ATIVGAState { uint16_t cursor_size; uint32_t cursor_offset; QEMUCursor *cursor; + QEMUTimer vblank_timer; bitbang_i2c_interface bbi2c; MemoryRegion io; MemoryRegion mm; diff --git a/hw/display/ati_regs.h b/hw/display/ati_regs.h index d7155c93d5..ebd37ee30d 100644 --- a/hw/display/ati_regs.h +++ b/hw/display/ati_regs.h @@ -34,6 +34,7 @@ #define BUS_CNTL 0x0030 #define BUS_CNTL1 0x0034 #define GEN_INT_CNTL 0x0040 +#define GEN_INT_STATUS 0x0044 #define CRTC_GEN_CNTL 0x0050 #define CRTC_EXT_CNTL 0x0054 #define DAC_CNTL 0x0058 @@ -41,11 +42,20 @@ #define GPIO_DVI_DDC 0x0064 #define GPIO_MONID 0x0068 #define I2C_CNTL_1 0x0094 +#define AMCGPIO_MASK_MIR 0x009c +#define AMCGPIO_A_MIR 0x00a0 +#define AMCGPIO_Y_MIR 0x00a4 +#define AMCGPIO_EN_MIR 0x00a8 #define PALETTE_INDEX 0x00b0 #define PALETTE_DATA 0x00b4 #define CNFG_CNTL 0x00e0 #define GEN_RESET_CNTL 0x00f0 #define CNFG_MEMSIZE 0x00f8 +#define CONFIG_APER_0_BASE 0x0100 +#define CONFIG_APER_1_BASE 0x0104 +#define CONFIG_APER_SIZE 0x0108 +#define CONFIG_REG_1_BASE 0x010c +#define CONFIG_REG_APER_SIZE 0x0110 #define MEM_CNTL 0x0140 #define MC_FB_LOCATION 0x0148 #define MC_AGP_LOCATION 0x014C @@ -307,7 +317,14 @@ #define XPLL_FB_DIV_MASK 0x0000FF00 #define X_MPLL_REF_DIV_MASK 0x000000FF +/* GEN_INT_CNTL) */ +#define CRTC_VBLANK_INT 0x00000001 +#define CRTC_VLINE_INT 0x00000002 +#define CRTC_VSYNC_INT 0x00000004 + /* Config control values (CONFIG_CNTL) */ +#define APER_0_ENDIAN 0x00000003 +#define APER_1_ENDIAN 0x0000000c #define CFG_VGA_IO_DIS 0x00000400 /* CRTC control values (CRTC_GEN_CNTL) */ diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 5b0ec1b89e..034e413fd0 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -27,7 +27,7 @@ #include "qemu/bitmap.h" #include "qemu/error-report.h" #include "hw/pci/pci.h" -#include "qom/cpu.h" +#include "hw/core/cpu.h" #include "target/i386/cpu.h" #include "hw/misc/pvpanic.h" #include "hw/timer/hpet.h" diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 697c33606a..c14ed86439 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -76,7 +76,7 @@ #include "qapi/error.h" #include "qapi/qapi-visit-common.h" #include "qapi/visitor.h" -#include "qom/cpu.h" +#include "hw/core/cpu.h" #include "hw/nmi.h" #include "hw/usb.h" #include "hw/i386/intel_iommu.h" diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 7af591daac..1d7da7baa2 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -23,7 +23,7 @@ #include "hw/sysbus.h" #include "gic_internal.h" #include "qapi/error.h" -#include "qom/cpu.h" +#include "hw/core/cpu.h" #include "qemu/log.h" #include "qemu/module.h" #include "trace.h" diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c index 8f5f4c8e94..f0c551d43f 100644 --- a/hw/intc/arm_gicv3_common.c +++ b/hw/intc/arm_gicv3_common.c @@ -24,7 +24,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/module.h" -#include "qom/cpu.h" +#include "hw/core/cpu.h" #include "hw/intc/arm_gicv3_common.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index eec9eb31c1..17c292e306 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -49,7 +49,7 @@ #include "exec/address-spaces.h" #include "sysemu/runstate.h" #include "sysemu/sysemu.h" -#include "qom/cpu.h" +#include "hw/core/cpu.h" #include "hw/nvram/fw_cfg.h" #include "qemu/cutils.h" diff --git a/hw/misc/imx6_src.c b/hw/misc/imx6_src.c index 8ab18967b5..dd99cc7acf 100644 --- a/hw/misc/imx6_src.c +++ b/hw/misc/imx6_src.c @@ -16,7 +16,7 @@ #include "qemu/main-loop.h" #include "qemu/module.h" #include "arm-powerctl.h" -#include "qom/cpu.h" +#include "hw/core/cpu.h" #ifndef DEBUG_IMX6_SRC #define DEBUG_IMX6_SRC 0 diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 64fc2255cc..baedadf20b 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -49,7 +49,7 @@ #include "mmu-hash64.h" #include "mmu-book3s-v3.h" #include "cpu-models.h" -#include "qom/cpu.h" +#include "hw/core/cpu.h" #include "hw/boards.h" #include "hw/ppc/ppc.h" diff --git a/hw/timer/a9gtimer.c b/hw/timer/a9gtimer.c index 75f1867174..4c634c83b1 100644 --- a/hw/timer/a9gtimer.c +++ b/hw/timer/a9gtimer.c @@ -31,7 +31,7 @@ #include "qemu/bitops.h" #include "qemu/log.h" #include "qemu/module.h" -#include "qom/cpu.h" +#include "hw/core/cpu.h" #ifndef A9_GTIMER_ERR_DEBUG #define A9_GTIMER_ERR_DEBUG 0 diff --git a/hw/timer/arm_mptimer.c b/hw/timer/arm_mptimer.c index 983e61847e..9f63abef10 100644 --- a/hw/timer/arm_mptimer.c +++ b/hw/timer/arm_mptimer.c @@ -29,7 +29,7 @@ #include "qapi/error.h" #include "qemu/main-loop.h" #include "qemu/module.h" -#include "qom/cpu.h" +#include "hw/core/cpu.h" #define PTIMER_POLICY \ (PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD | \ diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 9ca7b87a80..56ab2f457f 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -1838,6 +1838,9 @@ static int ehci_state_fetchqtd(EHCIQueue *q) ehci_set_state(q->ehci, q->async, EST_EXECUTING); break; } + } else if (q->dev == NULL) { + ehci_trace_guest_bug(q->ehci, "no device attached to queue"); + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); } else { p = ehci_alloc_packet(q); p->qtdaddr = q->qtdaddr; diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index f698224c8a..f578264948 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -2543,6 +2543,9 @@ static void xhci_process_commands(XHCIState *xhci) case CR_GET_PORT_BANDWIDTH: event.ccode = xhci_get_port_bandwidth(xhci, trb.parameter); break; + case CR_NOOP: + event.ccode = CC_SUCCESS; + break; case CR_VENDOR_NEC_FIRMWARE_REVISION: if (xhci->nec_quirks) { event.type = 48; /* NEC reply */ diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index fc9fe0c00f..e0f5ca6f81 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -819,8 +819,8 @@ static void usbredir_handle_interrupt_in_data(USBRedirDevice *dev, USBPacket *p, uint8_t ep) { /* Input interrupt endpoint, buffered packet input */ - struct buf_packet *intp; - int status, len; + struct buf_packet *intp, *intp_to_free; + int status, len, sum; if (!dev->endpoint[EP2I(ep)].interrupt_started && !dev->endpoint[EP2I(ep)].interrupt_error) { @@ -839,9 +839,17 @@ static void usbredir_handle_interrupt_in_data(USBRedirDevice *dev, dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0; } - intp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq); + /* check for completed interrupt message (with all fragments) */ + sum = 0; + QTAILQ_FOREACH(intp, &dev->endpoint[EP2I(ep)].bufpq, next) { + sum += intp->len; + if (intp->len < dev->endpoint[EP2I(ep)].max_packet_size || + sum >= p->iov.size) + break; + } + if (intp == NULL) { - DPRINTF2("interrupt-token-in ep %02X, no intp\n", ep); + DPRINTF2("interrupt-token-in ep %02X, no intp, buffered %d\n", ep, sum); /* Check interrupt_error for stream errors */ status = dev->endpoint[EP2I(ep)].interrupt_error; dev->endpoint[EP2I(ep)].interrupt_error = 0; @@ -852,18 +860,42 @@ static void usbredir_handle_interrupt_in_data(USBRedirDevice *dev, } return; } - DPRINTF("interrupt-token-in ep %02X status %d len %d\n", ep, - intp->status, intp->len); - status = intp->status; - len = intp->len; - if (len > p->iov.size) { - ERROR("received int data is larger then packet ep %02X\n", ep); - len = p->iov.size; - status = usb_redir_babble; + /* copy of completed interrupt message */ + sum = 0; + status = usb_redir_success; + intp_to_free = NULL; + QTAILQ_FOREACH(intp, &dev->endpoint[EP2I(ep)].bufpq, next) { + if (intp_to_free) { + bufp_free(dev, intp_to_free, ep); + } + DPRINTF("interrupt-token-in ep %02X fragment status %d len %d\n", ep, + intp->status, intp->len); + + sum += intp->len; + len = intp->len; + if (status == usb_redir_success) { + status = intp->status; + } + if (sum > p->iov.size) { + ERROR("received int data is larger then packet ep %02X\n", ep); + len -= (sum - p->iov.size); + sum = p->iov.size; + status = usb_redir_babble; + } + + usb_packet_copy(p, intp->data, len); + + intp_to_free = intp; + if (intp->len < dev->endpoint[EP2I(ep)].max_packet_size || + sum >= p->iov.size) + break; + } + if (intp_to_free) { + bufp_free(dev, intp_to_free, ep); } - usb_packet_copy(p, intp->data, len); - bufp_free(dev, intp, ep); + DPRINTF("interrupt-token-in ep %02X summary status %d len %d\n", ep, + status, sum); usbredir_handle_status(dev, p, status); } @@ -1499,6 +1531,11 @@ static void usbredir_check_bulk_receiving(USBRedirDevice *dev) for (i = EP2I(USB_DIR_IN); i < MAX_ENDPOINTS; i++) { dev->endpoint[i].bulk_receiving_enabled = 0; } + + if (dev->interface_info.interface_count == NO_INTERFACE_INFO) { + return; + } + for (i = 0; i < dev->interface_info.interface_count; i++) { quirks = usb_get_quirks(dev->device_info.vendor_id, dev->device_info.product_id, @@ -2036,22 +2073,17 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id, } if (ep & USB_DIR_IN) { - bool q_was_empty; - if (dev->endpoint[EP2I(ep)].interrupt_started == 0) { DPRINTF("received int packet while not started ep %02X\n", ep); free(data); return; } - q_was_empty = QTAILQ_EMPTY(&dev->endpoint[EP2I(ep)].bufpq); - /* bufp_alloc also adds the packet to the ep queue */ bufp_alloc(dev, data, data_len, interrupt_packet->status, ep, data); - if (q_was_empty) { - usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f), 0); - } + /* insufficient data solved with USB_RET_NAK */ + usb_wakeup(usb_ep_get(&dev->dev, USB_TOKEN_IN, ep & 0x0f), 0); } else { /* * We report output interrupt packets as completed directly upon |