diff options
65 files changed, 1006 insertions, 486 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 7efaccf5fb..7d17f83868 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -158,7 +158,6 @@ Guest CPU Cores (KVM): ---------------------- Overall -M: Gleb Natapov <gleb@redhat.com> M: Paolo Bonzini <pbonzini@redhat.com> L: kvm@vger.kernel.org S: Supported @@ -176,12 +175,14 @@ S: Maintained F: target-ppc/kvm.c S390 +M: Christian Borntraeger <borntraeger@de.ibm.com> +M: Cornelia Huck <cornelia.huck@de.ibm.com> M: Alexander Graf <agraf@suse.de> S: Maintained F: target-s390x/kvm.c +F: hw/intc/s390_flic.[hc] X86 -M: Gleb Natapov <gleb@redhat.com> M: Marcelo Tosatti <mtosatti@redhat.com> L: kvm@vger.kernel.org S: Supported @@ -495,10 +496,13 @@ F: hw/s390x/s390-*.c S390 Virtio-ccw M: Cornelia Huck <cornelia.huck@de.ibm.com> +M: Christian Borntraeger <borntraeger@de.ibm.com> M: Alexander Graf <agraf@suse.de> S: Supported F: hw/s390x/s390-virtio-ccw.c F: hw/s390x/css.[hc] +F: hw/s390x/sclp*.[hc] +F: hw/s390x/ipl*.[hc] T: git git://github.com/cohuck/qemu virtio-ccw-upstr UniCore32 Machines @@ -629,6 +633,7 @@ F: hw/block/virtio-blk.c virtio-ccw M: Cornelia Huck <cornelia.huck@de.ibm.com> +M: Christian Borntraeger <borntraeger@de.ibm.com> S: Supported F: hw/s390x/virtio-ccw.[hc] T: git git://github.com/cohuck/qemu virtio-ccw-upstr @@ -4107,7 +4107,11 @@ echo "vhost-net support $vhost_net" echo "vhost-scsi support $vhost_scsi" echo "Trace backend $trace_backend" echo "Trace output file $trace_file-<pid>" +if test "$spice" = "yes"; then echo "spice support $spice ($spice_protocol_version/$spice_server_version)" +else +echo "spice support $spice" +fi echo "rbd support $rbd" echo "xfsctl support $xfs" echo "nss used $smartcard_nss" @@ -1117,8 +1117,13 @@ void resume_all_vcpus(void) } } +/* For temporary buffers for forming a name */ +#define VCPU_THREAD_NAME_SIZE 16 + static void qemu_tcg_init_vcpu(CPUState *cpu) { + char thread_name[VCPU_THREAD_NAME_SIZE]; + tcg_cpu_address_space_init(cpu, cpu->as); /* share a single thread for all cpus with TCG */ @@ -1127,8 +1132,10 @@ static void qemu_tcg_init_vcpu(CPUState *cpu) cpu->halt_cond = g_malloc0(sizeof(QemuCond)); qemu_cond_init(cpu->halt_cond); tcg_halt_cond = cpu->halt_cond; - qemu_thread_create(cpu->thread, qemu_tcg_cpu_thread_fn, cpu, - QEMU_THREAD_JOINABLE); + snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/TCG", + cpu->cpu_index); + qemu_thread_create(cpu->thread, thread_name, qemu_tcg_cpu_thread_fn, + cpu, QEMU_THREAD_JOINABLE); #ifdef _WIN32 cpu->hThread = qemu_thread_get_handle(cpu->thread); #endif @@ -1144,11 +1151,15 @@ static void qemu_tcg_init_vcpu(CPUState *cpu) static void qemu_kvm_start_vcpu(CPUState *cpu) { + char thread_name[VCPU_THREAD_NAME_SIZE]; + cpu->thread = g_malloc0(sizeof(QemuThread)); cpu->halt_cond = g_malloc0(sizeof(QemuCond)); qemu_cond_init(cpu->halt_cond); - qemu_thread_create(cpu->thread, qemu_kvm_cpu_thread_fn, cpu, - QEMU_THREAD_JOINABLE); + snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/KVM", + cpu->cpu_index); + qemu_thread_create(cpu->thread, thread_name, qemu_kvm_cpu_thread_fn, + cpu, QEMU_THREAD_JOINABLE); while (!cpu->created) { qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex); } @@ -1156,10 +1167,14 @@ static void qemu_kvm_start_vcpu(CPUState *cpu) static void qemu_dummy_start_vcpu(CPUState *cpu) { + char thread_name[VCPU_THREAD_NAME_SIZE]; + cpu->thread = g_malloc0(sizeof(QemuThread)); cpu->halt_cond = g_malloc0(sizeof(QemuCond)); qemu_cond_init(cpu->halt_cond); - qemu_thread_create(cpu->thread, qemu_dummy_cpu_thread_fn, cpu, + snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/DUMMY", + cpu->cpu_index); + qemu_thread_create(cpu->thread, thread_name, qemu_dummy_cpu_thread_fn, cpu, QEMU_THREAD_JOINABLE); while (!cpu->created) { qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex); diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index 2237edb4eb..d1c7ad4574 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -358,7 +358,7 @@ static void start_data_plane_bh(void *opaque) qemu_bh_delete(s->start_bh); s->start_bh = NULL; - qemu_thread_create(&s->thread, data_plane_thread, + qemu_thread_create(&s->thread, "data_plane", data_plane_thread, s, QEMU_THREAD_JOINABLE); } diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index b1a7ebb8e3..b667d31de5 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -643,6 +643,21 @@ static inline char acpi_get_hex(uint32_t val) #define ACPI_PCIHP_SIZEOF (*ssdt_pcihp_end - *ssdt_pcihp_start) #define ACPI_PCIHP_AML (ssdp_pcihp_aml + *ssdt_pcihp_start) +#define ACPI_PCINOHP_OFFSET_HEX (*ssdt_pcinohp_name - *ssdt_pcinohp_start + 1) +#define ACPI_PCINOHP_OFFSET_ADR (*ssdt_pcinohp_adr - *ssdt_pcinohp_start) +#define ACPI_PCINOHP_SIZEOF (*ssdt_pcinohp_end - *ssdt_pcinohp_start) +#define ACPI_PCINOHP_AML (ssdp_pcihp_aml + *ssdt_pcinohp_start) + +#define ACPI_PCIVGA_OFFSET_HEX (*ssdt_pcivga_name - *ssdt_pcivga_start + 1) +#define ACPI_PCIVGA_OFFSET_ADR (*ssdt_pcivga_adr - *ssdt_pcivga_start) +#define ACPI_PCIVGA_SIZEOF (*ssdt_pcivga_end - *ssdt_pcivga_start) +#define ACPI_PCIVGA_AML (ssdp_pcihp_aml + *ssdt_pcivga_start) + +#define ACPI_PCIQXL_OFFSET_HEX (*ssdt_pciqxl_name - *ssdt_pciqxl_start + 1) +#define ACPI_PCIQXL_OFFSET_ADR (*ssdt_pciqxl_adr - *ssdt_pciqxl_start) +#define ACPI_PCIQXL_SIZEOF (*ssdt_pciqxl_end - *ssdt_pciqxl_start) +#define ACPI_PCIQXL_AML (ssdp_pcihp_aml + *ssdt_pciqxl_start) + #define ACPI_SSDT_SIGNATURE 0x54445353 /* SSDT */ #define ACPI_SSDT_HEADER_LENGTH 36 @@ -677,6 +692,33 @@ static void patch_pcihp(int slot, uint8_t *ssdt_ptr) ssdt_ptr[ACPI_PCIHP_OFFSET_ADR + 2] = slot; } +static void patch_pcinohp(int slot, uint8_t *ssdt_ptr) +{ + unsigned devfn = PCI_DEVFN(slot, 0); + + ssdt_ptr[ACPI_PCINOHP_OFFSET_HEX] = acpi_get_hex(devfn >> 4); + ssdt_ptr[ACPI_PCINOHP_OFFSET_HEX + 1] = acpi_get_hex(devfn); + ssdt_ptr[ACPI_PCINOHP_OFFSET_ADR + 2] = slot; +} + +static void patch_pcivga(int slot, uint8_t *ssdt_ptr) +{ + unsigned devfn = PCI_DEVFN(slot, 0); + + ssdt_ptr[ACPI_PCIVGA_OFFSET_HEX] = acpi_get_hex(devfn >> 4); + ssdt_ptr[ACPI_PCIVGA_OFFSET_HEX + 1] = acpi_get_hex(devfn); + ssdt_ptr[ACPI_PCIVGA_OFFSET_ADR + 2] = slot; +} + +static void patch_pciqxl(int slot, uint8_t *ssdt_ptr) +{ + unsigned devfn = PCI_DEVFN(slot, 0); + + ssdt_ptr[ACPI_PCIQXL_OFFSET_HEX] = acpi_get_hex(devfn >> 4); + ssdt_ptr[ACPI_PCIQXL_OFFSET_HEX + 1] = acpi_get_hex(devfn); + ssdt_ptr[ACPI_PCIQXL_OFFSET_ADR + 2] = slot; +} + /* Assign BSEL property to all buses. In the future, this can be changed * to only assign to buses that support hotplug. */ @@ -737,6 +779,10 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state) AcpiBuildPciBusHotplugState *parent = child->parent; GArray *bus_table = build_alloc_array(); DECLARE_BITMAP(slot_hotplug_enable, PCI_SLOT_MAX); + DECLARE_BITMAP(slot_device_present, PCI_SLOT_MAX); + DECLARE_BITMAP(slot_device_system, PCI_SLOT_MAX); + DECLARE_BITMAP(slot_device_vga, PCI_SLOT_MAX); + DECLARE_BITMAP(slot_device_qxl, PCI_SLOT_MAX); uint8_t op; int i; QObject *bsel; @@ -764,40 +810,82 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state) build_append_byte(bus_table, 0x08); /* NameOp */ build_append_nameseg(bus_table, "BSEL"); build_append_int(bus_table, qint_get_int(qobject_to_qint(bsel))); - memset(slot_hotplug_enable, 0xff, sizeof slot_hotplug_enable); + } else { + /* No bsel - no slots are hot-pluggable */ + memset(slot_hotplug_enable, 0x00, sizeof slot_hotplug_enable); + } - for (i = 0; i < ARRAY_SIZE(bus->devices); ++i) { - DeviceClass *dc; - PCIDeviceClass *pc; - PCIDevice *pdev = bus->devices[i]; + memset(slot_device_present, 0x00, sizeof slot_device_present); + memset(slot_device_system, 0x00, sizeof slot_device_present); + memset(slot_device_vga, 0x00, sizeof slot_device_vga); + memset(slot_device_qxl, 0x00, sizeof slot_device_qxl); - if (!pdev) { - continue; - } + for (i = 0; i < ARRAY_SIZE(bus->devices); i += PCI_FUNC_MAX) { + DeviceClass *dc; + PCIDeviceClass *pc; + PCIDevice *pdev = bus->devices[i]; + int slot = PCI_SLOT(i); - pc = PCI_DEVICE_GET_CLASS(pdev); - dc = DEVICE_GET_CLASS(pdev); + if (!pdev) { + continue; + } - if (!dc->hotpluggable || pc->is_bridge) { - int slot = PCI_SLOT(i); + set_bit(slot, slot_device_present); + pc = PCI_DEVICE_GET_CLASS(pdev); + dc = DEVICE_GET_CLASS(pdev); - clear_bit(slot, slot_hotplug_enable); - } + if (pc->class_id == PCI_CLASS_BRIDGE_ISA) { + set_bit(slot, slot_device_system); } - /* Append Device object for each slot which supports eject */ - for (i = 0; i < PCI_SLOT_MAX; i++) { - bool can_eject = test_bit(i, slot_hotplug_enable); - if (can_eject) { - void *pcihp = acpi_data_push(bus_table, - ACPI_PCIHP_SIZEOF); - memcpy(pcihp, ACPI_PCIHP_AML, ACPI_PCIHP_SIZEOF); - patch_pcihp(i, pcihp); - bus_hotplug_support = true; + if (pc->class_id == PCI_CLASS_DISPLAY_VGA) { + set_bit(slot, slot_device_vga); + + if (object_dynamic_cast(OBJECT(pdev), "qxl-vga")) { + set_bit(slot, slot_device_qxl); } } + if (!dc->hotpluggable || pc->is_bridge) { + clear_bit(slot, slot_hotplug_enable); + } + } + + /* Append Device object for each slot */ + for (i = 0; i < PCI_SLOT_MAX; i++) { + bool can_eject = test_bit(i, slot_hotplug_enable); + bool present = test_bit(i, slot_device_present); + bool vga = test_bit(i, slot_device_vga); + bool qxl = test_bit(i, slot_device_qxl); + bool system = test_bit(i, slot_device_system); + if (can_eject) { + void *pcihp = acpi_data_push(bus_table, + ACPI_PCIHP_SIZEOF); + memcpy(pcihp, ACPI_PCIHP_AML, ACPI_PCIHP_SIZEOF); + patch_pcihp(i, pcihp); + bus_hotplug_support = true; + } else if (qxl) { + void *pcihp = acpi_data_push(bus_table, + ACPI_PCIQXL_SIZEOF); + memcpy(pcihp, ACPI_PCIQXL_AML, ACPI_PCIQXL_SIZEOF); + patch_pciqxl(i, pcihp); + } else if (vga) { + void *pcihp = acpi_data_push(bus_table, + ACPI_PCIVGA_SIZEOF); + memcpy(pcihp, ACPI_PCIVGA_AML, ACPI_PCIVGA_SIZEOF); + patch_pcivga(i, pcihp); + } else if (system) { + /* Nothing to do: system devices are in DSDT. */ + } else if (present) { + void *pcihp = acpi_data_push(bus_table, + ACPI_PCINOHP_SIZEOF); + memcpy(pcihp, ACPI_PCINOHP_AML, ACPI_PCINOHP_SIZEOF); + patch_pcinohp(i, pcihp); + } + } + + if (bsel) { method = build_alloc_method("DVNT", 2); for (i = 0; i < PCI_SLOT_MAX; i++) { @@ -976,7 +1064,14 @@ build_ssdt(GArray *table_data, GArray *linker, { AcpiBuildPciBusHotplugState hotplug_state; - PCIBus *bus = find_i440fx(); /* TODO: Q35 support */ + Object *pci_host; + PCIBus *bus = NULL; + bool ambiguous; + + pci_host = object_resolve_path_type("", TYPE_PCI_HOST_BRIDGE, &ambiguous); + if (!ambiguous && pci_host) { + bus = PCI_HOST_BRIDGE(pci_host)->bus; + } build_pci_bus_state_init(&hotplug_state, NULL); diff --git a/hw/i386/acpi-dsdt.dsl b/hw/i386/acpi-dsdt.dsl index b23d5e0eac..0a1e252d21 100644 --- a/hw/i386/acpi-dsdt.dsl +++ b/hw/i386/acpi-dsdt.dsl @@ -80,6 +80,8 @@ DefinitionBlock ( Name(_HID, EisaId("PNP0A03")) Name(_ADR, 0x00) Name(_UID, 1) +//#define PX13 S0B_ +// External(PX13, DeviceObj) } } @@ -88,34 +90,6 @@ DefinitionBlock ( /**************************************************************** - * VGA - ****************************************************************/ - - Scope(\_SB.PCI0) { - Device(VGA) { - Name(_ADR, 0x00020000) - OperationRegion(PCIC, PCI_Config, Zero, 0x4) - Field(PCIC, DWordAcc, NoLock, Preserve) { - VEND, 32 - } - Method(_S1D, 0, NotSerialized) { - Return (0x00) - } - Method(_S2D, 0, NotSerialized) { - Return (0x00) - } - Method(_S3D, 0, NotSerialized) { - If (LEqual(VEND, 0x1001b36)) { - Return (0x03) // QXL - } Else { - Return (0x00) - } - } - } - } - - -/**************************************************************** * PIIX4 PM ****************************************************************/ @@ -132,6 +106,9 @@ DefinitionBlock ( ****************************************************************/ Scope(\_SB.PCI0) { + + External(ISA, DeviceObj) + Device(ISA) { Name(_ADR, 0x00010000) diff --git a/hw/i386/acpi-dsdt.hex.generated b/hw/i386/acpi-dsdt.hex.generated index 1e58801b2a..94c6e8e114 100644 --- a/hw/i386/acpi-dsdt.hex.generated +++ b/hw/i386/acpi-dsdt.hex.generated @@ -3,12 +3,12 @@ static unsigned char AcpiDsdtAmlCode[] = { 0x53, 0x44, 0x54, -0x87, +0x85, 0x11, 0x0, 0x0, 0x1, -0xb8, +0x8b, 0x42, 0x58, 0x50, @@ -146,7 +146,7 @@ static unsigned char AcpiDsdtAmlCode[] = { 0x1, 0x10, 0x4e, -0x15, +0x18, 0x2e, 0x5f, 0x53, @@ -163,9 +163,9 @@ static unsigned char AcpiDsdtAmlCode[] = { 0x53, 0x11, 0x42, -0x7, 0xa, -0x6e, +0xa, +0x9e, 0x88, 0xd, 0x0, @@ -217,11 +217,59 @@ static unsigned char AcpiDsdtAmlCode[] = { 0x0, 0xd, 0xff, +0xad, +0x0, +0x0, +0x0, +0xa1, +0x88, +0xd, +0x0, +0x1, +0xc, +0x3, +0x0, +0x0, +0xf, +0xae, 0xff, +0xae, +0x0, 0x0, +0xf1, 0x0, +0x88, +0xd, +0x0, +0x1, +0xc, +0x3, 0x0, -0xf3, +0x0, +0x20, +0xaf, +0xdf, +0xaf, +0x0, +0x0, +0xc0, +0x0, +0x88, +0xd, +0x0, +0x1, +0xc, +0x3, +0x0, +0x0, +0xe4, +0xaf, +0xff, +0xff, +0x0, +0x0, +0x1c, +0x50, 0x87, 0x17, 0x0, @@ -347,7 +395,7 @@ static unsigned char AcpiDsdtAmlCode[] = { 0x45, 0x53, 0xa, -0x5c, +0x8c, 0x50, 0x53, 0x33, @@ -358,7 +406,7 @@ static unsigned char AcpiDsdtAmlCode[] = { 0x45, 0x53, 0xa, -0x60, +0x90, 0x50, 0x45, 0x33, @@ -369,7 +417,7 @@ static unsigned char AcpiDsdtAmlCode[] = { 0x45, 0x53, 0xa, -0x68, +0x98, 0x50, 0x4c, 0x33, @@ -638,103 +686,6 @@ static unsigned char AcpiDsdtAmlCode[] = { 0x79, 0x0, 0x10, -0x40, -0x6, -0x2e, -0x5f, -0x53, -0x42, -0x5f, -0x50, -0x43, -0x49, -0x30, -0x5b, -0x82, -0x43, -0x5, -0x56, -0x47, -0x41, -0x5f, -0x8, -0x5f, -0x41, -0x44, -0x52, -0xc, -0x0, -0x0, -0x2, -0x0, -0x5b, -0x80, -0x50, -0x43, -0x49, -0x43, -0x2, -0x0, -0xa, -0x4, -0x5b, -0x81, -0xb, -0x50, -0x43, -0x49, -0x43, -0x3, -0x56, -0x45, -0x4e, -0x44, -0x20, -0x14, -0x8, -0x5f, -0x53, -0x31, -0x44, -0x0, -0xa4, -0x0, -0x14, -0x8, -0x5f, -0x53, -0x32, -0x44, -0x0, -0xa4, -0x0, -0x14, -0x19, -0x5f, -0x53, -0x33, -0x44, -0x0, -0xa0, -0xe, -0x93, -0x56, -0x45, -0x4e, -0x44, -0xc, -0x36, -0x1b, -0x0, -0x1, -0xa4, -0xa, -0x3, -0xa1, -0x3, -0xa4, -0x0, -0x10, 0x25, 0x2e, 0x5f, @@ -860,7 +811,7 @@ static unsigned char AcpiDsdtAmlCode[] = { 0x4e, 0x1, 0x10, -0x4b, +0x4a, 0x1e, 0x2f, 0x3, @@ -878,7 +829,7 @@ static unsigned char AcpiDsdtAmlCode[] = { 0x5f, 0x5b, 0x82, -0x2d, +0x2c, 0x53, 0x4d, 0x43, @@ -898,9 +849,8 @@ static unsigned char AcpiDsdtAmlCode[] = { 0x53, 0x54, 0x41, -0xb, -0x0, -0xff, +0xa, +0xf0, 0x8, 0x5f, 0x43, @@ -4061,7 +4011,7 @@ static unsigned char AcpiDsdtAmlCode[] = { 0x1, 0x10, 0x47, -0xe, +0x11, 0x5f, 0x53, 0x42, @@ -4291,6 +4241,54 @@ static unsigned char AcpiDsdtAmlCode[] = { 0x3, 0x75, 0x60, +0x5b, +0x82, +0x2e, +0x50, +0x52, +0x45, +0x53, +0x8, +0x5f, +0x48, +0x49, +0x44, +0xd, +0x41, +0x43, +0x50, +0x49, +0x30, +0x30, +0x30, +0x34, +0x0, +0x8, +0x5f, +0x43, +0x52, +0x53, +0x11, +0xd, +0xa, +0xa, +0x47, +0x1, +0x0, +0xaf, +0x0, +0xaf, +0x0, +0x20, +0x79, +0x0, +0x8, +0x5f, +0x53, +0x54, +0x41, +0xa, +0xb, 0x10, 0x42, 0xc, @@ -4488,5 +4486,5 @@ static unsigned char AcpiDsdtAmlCode[] = { 0x0 }; static unsigned short piix_dsdt_applesmc_sta[] = { -0x384 +0x353 }; diff --git a/hw/i386/q35-acpi-dsdt.dsl b/hw/i386/q35-acpi-dsdt.dsl index d618e9e2d2..f4d2a2daee 100644 --- a/hw/i386/q35-acpi-dsdt.dsl +++ b/hw/i386/q35-acpi-dsdt.dsl @@ -72,6 +72,8 @@ DefinitionBlock ( Name(_ADR, 0x00) Name(_UID, 1) + External(ISA, DeviceObj) + // _OSC: based on sample of ACPI3.0b spec Name(SUPP, 0) // PCI _OSC Support Field value Name(CTRL, 0) // PCI _OSC Control Field value @@ -134,34 +136,13 @@ DefinitionBlock ( /**************************************************************** - * VGA - ****************************************************************/ - - Scope(\_SB.PCI0) { - Device(VGA) { - Name(_ADR, 0x00010000) - Method(_S1D, 0, NotSerialized) { - Return (0x00) - } - Method(_S2D, 0, NotSerialized) { - Return (0x00) - } - Method(_S3D, 0, NotSerialized) { - Return (0x00) - } - } - } - - -/**************************************************************** * LPC ISA bridge ****************************************************************/ Scope(\_SB.PCI0) { /* PCI D31:f0 LPC ISA bridge */ Device(ISA) { - /* PCI D31:f0 */ - Name(_ADR, 0x001f0000) + Name (_ADR, 0x001F0000) // _ADR: Address /* ICH9 PCI to ISA irq remapping */ OperationRegion(PIRQ, PCI_Config, 0x60, 0x0C) diff --git a/hw/i386/q35-acpi-dsdt.hex.generated b/hw/i386/q35-acpi-dsdt.hex.generated index 6d885a9055..6c29f3b6d2 100644 --- a/hw/i386/q35-acpi-dsdt.hex.generated +++ b/hw/i386/q35-acpi-dsdt.hex.generated @@ -3,12 +3,12 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { 0x53, 0x44, 0x54, -0xdf, +0xd7, 0x1c, 0x0, 0x0, 0x1, -0xff, +0x3e, 0x42, 0x58, 0x50, @@ -415,11 +415,11 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { 0x0, 0x0, 0x0, -0xf7, +0xd7, 0xc, 0x0, 0x0, -0xf8, +0xd8, 0xc, 0x88, 0xd, @@ -853,61 +853,6 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { 0x79, 0x0, 0x10, -0x36, -0x2e, -0x5f, -0x53, -0x42, -0x5f, -0x50, -0x43, -0x49, -0x30, -0x5b, -0x82, -0x2a, -0x56, -0x47, -0x41, -0x5f, -0x8, -0x5f, -0x41, -0x44, -0x52, -0xc, -0x0, -0x0, -0x1, -0x0, -0x14, -0x8, -0x5f, -0x53, -0x31, -0x44, -0x0, -0xa4, -0x0, -0x14, -0x8, -0x5f, -0x53, -0x32, -0x44, -0x0, -0xa4, -0x0, -0x14, -0x8, -0x5f, -0x53, -0x33, -0x44, -0x0, -0xa4, -0x0, -0x10, 0x4c, 0x7, 0x2e, @@ -1033,7 +978,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { 0x4e, 0x1, 0x10, -0x4b, +0x4a, 0x1e, 0x2f, 0x3, @@ -1051,7 +996,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { 0x5f, 0x5b, 0x82, -0x2d, +0x2c, 0x53, 0x4d, 0x43, @@ -1071,9 +1016,8 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { 0x53, 0x54, 0x41, -0xb, -0x0, -0xff, +0xa, +0xf0, 0x8, 0x5f, 0x43, @@ -7016,7 +6960,7 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { 0x1, 0x10, 0x47, -0xe, +0x11, 0x5f, 0x53, 0x42, @@ -7121,8 +7065,8 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { 0x54, 0x1, 0xb, -0x0, -0xaf, +0xd8, +0xc, 0xa, 0x20, 0x5b, @@ -7246,6 +7190,54 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { 0x3, 0x75, 0x60, +0x5b, +0x82, +0x2e, +0x50, +0x52, +0x45, +0x53, +0x8, +0x5f, +0x48, +0x49, +0x44, +0xd, +0x41, +0x43, +0x50, +0x49, +0x30, +0x30, +0x30, +0x34, +0x0, +0x8, +0x5f, +0x43, +0x52, +0x53, +0x11, +0xd, +0xa, +0xa, +0x47, +0x1, +0xd8, +0xc, +0xd8, +0xc, +0x0, +0x20, +0x79, +0x0, +0x8, +0x5f, +0x53, +0x54, +0x41, +0xa, +0xb, 0x10, 0x4f, 0x8, @@ -7392,5 +7384,5 @@ static unsigned char Q35AcpiDsdtAmlCode[] = { 0x0 }; static unsigned short q35_dsdt_applesmc_sta[] = { -0x431 +0x3fa }; diff --git a/hw/i386/ssdt-pcihp.dsl b/hw/i386/ssdt-pcihp.dsl index cc245c3e7c..ac91c05836 100644 --- a/hw/i386/ssdt-pcihp.dsl +++ b/hw/i386/ssdt-pcihp.dsl @@ -46,5 +46,55 @@ DefinitionBlock ("ssdt-pcihp.aml", "SSDT", 0x01, "BXPC", "BXSSDTPCIHP", 0x1) } } + ACPI_EXTRACT_DEVICE_START ssdt_pcinohp_start + ACPI_EXTRACT_DEVICE_END ssdt_pcinohp_end + ACPI_EXTRACT_DEVICE_STRING ssdt_pcinohp_name + + // Extract the offsets of the device name, address dword and the slot + // name byte - we fill them in for each device. + Device(SBB) { + ACPI_EXTRACT_NAME_DWORD_CONST ssdt_pcinohp_adr + Name(_ADR, 0xAA0000) + } + + ACPI_EXTRACT_DEVICE_START ssdt_pcivga_start + ACPI_EXTRACT_DEVICE_END ssdt_pcivga_end + ACPI_EXTRACT_DEVICE_STRING ssdt_pcivga_name + + // Extract the offsets of the device name, address dword and the slot + // name byte - we fill them in for each device. + Device(SCC) { + ACPI_EXTRACT_NAME_DWORD_CONST ssdt_pcivga_adr + Name(_ADR, 0xAA0000) + Method(_S1D, 0, NotSerialized) { + Return (0x00) + } + Method(_S2D, 0, NotSerialized) { + Return (0x00) + } + Method(_S3D, 0, NotSerialized) { + Return (0x00) + } + } + + ACPI_EXTRACT_DEVICE_START ssdt_pciqxl_start + ACPI_EXTRACT_DEVICE_END ssdt_pciqxl_end + ACPI_EXTRACT_DEVICE_STRING ssdt_pciqxl_name + + // Extract the offsets of the device name, address dword and the slot + // name byte - we fill them in for each device. + Device(SDD) { + ACPI_EXTRACT_NAME_DWORD_CONST ssdt_pciqxl_adr + Name(_ADR, 0xAA0000) + Method(_S1D, 0, NotSerialized) { + Return (0x00) + } + Method(_S2D, 0, NotSerialized) { + Return (0x00) + } + Method(_S3D, 0, NotSerialized) { + Return (0x03) // QXL + } + } } } diff --git a/hw/i386/ssdt-pcihp.hex.generated b/hw/i386/ssdt-pcihp.hex.generated index 610a631fd1..b599b4663c 100644 --- a/hw/i386/ssdt-pcihp.hex.generated +++ b/hw/i386/ssdt-pcihp.hex.generated @@ -1,23 +1,38 @@ static unsigned char ssdt_pcihp_name[] = { -0x33 +0x34 +}; +static unsigned char ssdt_pcivga_end[] = { +0x99 +}; +static unsigned char ssdt_pcivga_name[] = { +0x70 }; static unsigned char ssdt_pcihp_adr[] = { -0x44 +0x45 +}; +static unsigned char ssdt_pcinohp_end[] = { +0x6d }; static unsigned char ssdt_pcihp_end[] = { -0x5b +0x5c +}; +static unsigned char ssdt_pciqxl_start[] = { +0x99 +}; +static unsigned char ssdt_pcinohp_name[] = { +0x5f }; static unsigned char ssdp_pcihp_aml[] = { 0x53, 0x53, 0x44, 0x54, -0x5b, +0xc6, 0x0, 0x0, 0x0, 0x1, -0xe8, +0x6b, 0x42, 0x58, 0x50, @@ -45,7 +60,8 @@ static unsigned char ssdp_pcihp_aml[] = { 0x13, 0x20, 0x10, -0x36, +0x41, +0xa, 0x5c, 0x2e, 0x5f, @@ -98,11 +114,138 @@ static unsigned char ssdp_pcihp_aml[] = { 0x5f, 0x53, 0x55, -0x4e +0x4e, +0x5b, +0x82, +0xf, +0x53, +0x42, +0x42, +0x5f, +0x8, +0x5f, +0x41, +0x44, +0x52, +0xc, +0x0, +0x0, +0xaa, +0x0, +0x5b, +0x82, +0x2a, +0x53, +0x43, +0x43, +0x5f, +0x8, +0x5f, +0x41, +0x44, +0x52, +0xc, +0x0, +0x0, +0xaa, +0x0, +0x14, +0x8, +0x5f, +0x53, +0x31, +0x44, +0x0, +0xa4, +0x0, +0x14, +0x8, +0x5f, +0x53, +0x32, +0x44, +0x0, +0xa4, +0x0, +0x14, +0x8, +0x5f, +0x53, +0x33, +0x44, +0x0, +0xa4, +0x0, +0x5b, +0x82, +0x2b, +0x53, +0x44, +0x44, +0x5f, +0x8, +0x5f, +0x41, +0x44, +0x52, +0xc, +0x0, +0x0, +0xaa, +0x0, +0x14, +0x8, +0x5f, +0x53, +0x31, +0x44, +0x0, +0xa4, +0x0, +0x14, +0x8, +0x5f, +0x53, +0x32, +0x44, +0x0, +0xa4, +0x0, +0x14, +0x9, +0x5f, +0x53, +0x33, +0x44, +0x0, +0xa4, +0xa, +0x3 +}; +static unsigned char ssdt_pciqxl_adr[] = { +0xa6 +}; +static unsigned char ssdt_pcinohp_adr[] = { +0x69 +}; +static unsigned char ssdt_pcivga_adr[] = { +0x7a +}; +static unsigned char ssdt_pciqxl_name[] = { +0x9c +}; +static unsigned char ssdt_pcivga_start[] = { +0x6d +}; +static unsigned char ssdt_pciqxl_end[] = { +0xc6 }; static unsigned char ssdt_pcihp_start[] = { -0x30 +0x31 }; static unsigned char ssdt_pcihp_id[] = { -0x3d +0x3e +}; +static unsigned char ssdt_pcinohp_start[] = { +0x5c }; diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c index 655b8c5011..29af3d741f 100644 --- a/hw/input/pckbd.c +++ b/hw/input/pckbd.c @@ -281,7 +281,7 @@ static void kbd_write_command(void *opaque, hwaddr addr, kbd_update_irq(s); break; case KBD_CCMD_READ_INPORT: - kbd_queue(s, 0x00, 0); + kbd_queue(s, 0x80, 0); break; case KBD_CCMD_READ_OUTPORT: kbd_queue(s, s->outport, 0); diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c index 652dd47a1c..b527932382 100644 --- a/hw/intc/ioapic.c +++ b/hw/intc/ioapic.c @@ -93,9 +93,6 @@ static void ioapic_set_irq(void *opaque, int vector, int level) uint32_t mask = 1 << vector; uint64_t entry = s->ioredtbl[vector]; - if (entry & (1 << IOAPIC_LVT_POLARITY_SHIFT)) { - level = !level; - } if (((entry >> IOAPIC_LVT_TRIGGER_MODE_SHIFT) & 1) == IOAPIC_TRIGGER_LEVEL) { /* level triggered */ diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 3c0342e17a..fd23c4627e 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -397,12 +397,15 @@ static int peer_detach(VirtIONet *n, int index) static void virtio_net_set_queues(VirtIONet *n) { int i; + int r; for (i = 0; i < n->max_queues; i++) { if (i < n->curr_queues) { - assert(!peer_attach(n, i)); + r = peer_attach(n, i); + assert(!r); } else { - assert(!peer_detach(n, i)); + r = peer_detach(n, i); + assert(!r); } } } diff --git a/hw/pci-host/pam.c b/hw/pci-host/pam.c index ec6be4676c..e1e95aabcd 100644 --- a/hw/pci-host/pam.c +++ b/hw/pci-host/pam.c @@ -68,7 +68,7 @@ void init_pam(DeviceState *dev, MemoryRegion *ram_memory, /* XXX: should distinguish read/write cases */ memory_region_init_alias(&mem->alias[0], OBJECT(dev), "pam-pci", pci_address_space, start, size); - memory_region_init_alias(&mem->alias[2], OBJECT(dev), "pam-pci", pci_address_space, + memory_region_init_alias(&mem->alias[2], OBJECT(dev), "pam-pci", ram_memory, start, size); for (i = 0; i < 4; ++i) { diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 8ecd11eca2..02cde6f96c 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -221,29 +221,23 @@ static void pcie_cap_slot_hotplug_common(PCIDevice *hotplug_dev, DeviceState *dev, uint8_t **exp_cap, Error **errp) { - PCIDevice *pci_dev = PCI_DEVICE(dev); *exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap; uint16_t sltsta = pci_get_word(*exp_cap + PCI_EXP_SLTSTA); - PCIE_DEV_PRINTF(pci_dev, "hotplug state: %d\n", state); + PCIE_DEV_PRINTF(PCI_DEVICE(dev), "hotplug state: %d\n", state); if (sltsta & PCI_EXP_SLTSTA_EIS) { /* the slot is electromechanically locked. * This error is propagated up to qdev and then to HMP/QMP. */ error_setg_errno(errp, -EBUSY, "slot is electromechanically locked"); } - - /* TODO: multifunction hot-plug. - * Right now, only a device of function = 0 is allowed to be - * hot plugged/unplugged. - */ - assert(PCI_FUNC(pci_dev->devfn) == 0); } void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { uint8_t *exp_cap; + PCIDevice *pci_dev = PCI_DEVICE(dev); pcie_cap_slot_hotplug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp); @@ -256,6 +250,12 @@ void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, return; } + /* TODO: multifunction hot-plug. + * Right now, only a device of function = 0 is allowed to be + * hot plugged/unplugged. + */ + assert(PCI_FUNC(pci_dev->devfn) == 0); + pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA, PCI_EXP_SLTSTA_PDS); pcie_cap_slot_event(PCI_DEVICE(hotplug_dev), PCI_EXP_HP_EV_PDC); diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c index aa913df853..7213c8909c 100644 --- a/hw/usb/ccid-card-emulated.c +++ b/hw/usb/ccid-card-emulated.c @@ -546,10 +546,10 @@ static int emulated_initfn(CCIDCardState *base) printf("%s: failed to initialize vcard\n", EMULATED_DEV_NAME); return -1; } - qemu_thread_create(&card->event_thread_id, event_thread, card, - QEMU_THREAD_JOINABLE); - qemu_thread_create(&card->apdu_thread_id, handle_apdu_thread, card, - QEMU_THREAD_JOINABLE); + qemu_thread_create(&card->event_thread_id, "ccid/event", event_thread, + card, QEMU_THREAD_JOINABLE); + qemu_thread_create(&card->apdu_thread_id, "ccid/apdu", handle_apdu_thread, + card, QEMU_THREAD_JOINABLE); return 0; } diff --git a/include/exec/memory.h b/include/exec/memory.h index 9101fc3a55..c084db2d9d 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -836,13 +836,13 @@ void memory_region_set_alias_offset(MemoryRegion *mr, hwaddr offset); /** - * memory_region_present: translate an address/size relative to a - * MemoryRegion into a #MemoryRegionSection. + * memory_region_present: checks if an address relative to a @parent + * translates into #MemoryRegion within @parent * * Answer whether a #MemoryRegion within @parent covers the address * @addr. * - * @parent: a MemoryRegion within which @addr is a relative address + * @parent: a #MemoryRegion within which @addr is a relative address * @addr: the area within @parent to be searched */ bool memory_region_present(MemoryRegion *parent, hwaddr addr); diff --git a/include/qemu/thread.h b/include/qemu/thread.h index 3e32c6531c..f7e3b9b290 100644 --- a/include/qemu/thread.h +++ b/include/qemu/thread.h @@ -52,12 +52,13 @@ void qemu_event_reset(QemuEvent *ev); void qemu_event_wait(QemuEvent *ev); void qemu_event_destroy(QemuEvent *ev); -void qemu_thread_create(QemuThread *thread, +void qemu_thread_create(QemuThread *thread, const char *name, void *(*start_routine)(void *), void *arg, int mode); void *qemu_thread_join(QemuThread *thread); void qemu_thread_get_self(QemuThread *thread); bool qemu_thread_is_self(QemuThread *thread); void qemu_thread_exit(void *retval); +void qemu_thread_naming(bool enable); #endif diff --git a/libcacard/vscclient.c b/libcacard/vscclient.c index 24f7088ecf..3477ab3e1b 100644 --- a/libcacard/vscclient.c +++ b/libcacard/vscclient.c @@ -269,7 +269,7 @@ on_host_init(VSCMsgHeader *mhHeader, VSCMsgInit *incoming) send_msg(VSC_ReaderRemove, VSCARD_MINIMAL_READER_ID, NULL, 0); /* launch the event_thread. This will trigger reader adds for all the * existing readers */ - qemu_thread_create(&thread_id, event_thread, NULL, 0); + qemu_thread_create(&thread_id, "vsc/event", event_thread, NULL, 0); return 0; } diff --git a/linux-user/alpha/syscall.h b/linux-user/alpha/syscall.h index 15a0100335..ed13d9a718 100644 --- a/linux-user/alpha/syscall.h +++ b/linux-user/alpha/syscall.h @@ -39,6 +39,7 @@ struct target_pt_regs { }; #define UNAME_MACHINE "alpha" +#define UNAME_MINIMUM_RELEASE "2.6.32" #undef TARGET_EDEADLK #define TARGET_EDEADLK 11 diff --git a/linux-user/arm/syscall.h b/linux-user/arm/syscall.h index 73f29314f6..ce2c2a8ed0 100644 --- a/linux-user/arm/syscall.h +++ b/linux-user/arm/syscall.h @@ -40,5 +40,6 @@ struct target_pt_regs { #else #define UNAME_MACHINE "armv5tel" #endif +#define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS diff --git a/linux-user/cris/syscall.h b/linux-user/cris/syscall.h index 832ee64bd8..f5783c0557 100644 --- a/linux-user/cris/syscall.h +++ b/linux-user/cris/syscall.h @@ -1,8 +1,8 @@ #ifndef CRIS_SYSCALL_H #define CRIS_SYSCALL_H 1 - #define UNAME_MACHINE "cris" +#define UNAME_MINIMUM_RELEASE "2.6.32" /* pt_regs not only specifices the format in the user-struct during * ptrace but is also the frame format used in the kernel prologue/epilogues diff --git a/linux-user/i386/syscall.h b/linux-user/i386/syscall.h index 12b8c3b672..9bfc1ad8f7 100644 --- a/linux-user/i386/syscall.h +++ b/linux-user/i386/syscall.h @@ -144,5 +144,6 @@ struct target_vm86plus_struct { }; #define UNAME_MACHINE "i686" +#define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS diff --git a/linux-user/m68k/syscall.h b/linux-user/m68k/syscall.h index 26187930db..889eaf7323 100644 --- a/linux-user/m68k/syscall.h +++ b/linux-user/m68k/syscall.h @@ -15,7 +15,7 @@ struct target_pt_regs { uint16_t __fill; }; - #define UNAME_MACHINE "m68k" +#define UNAME_MINIMUM_RELEASE "2.6.32" void do_m68k_simcall(CPUM68KState *, int); diff --git a/linux-user/main.c b/linux-user/main.c index be9491bc7d..dee10841c3 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2400,6 +2400,10 @@ static int do_break(CPUMIPSState *env, target_siginfo_t *info, ret = 0; break; default: + info->si_signo = TARGET_SIGTRAP; + info->si_errno = 0; + queue_signal(env, info->si_signo, &*info); + ret = 0; break; } diff --git a/linux-user/microblaze/syscall.h b/linux-user/microblaze/syscall.h index d550989d5e..5b5f6b447d 100644 --- a/linux-user/microblaze/syscall.h +++ b/linux-user/microblaze/syscall.h @@ -1,8 +1,8 @@ #ifndef MICROBLAZE_SYSCALLS_H #define MICROBLAZE_SYSCALLS_H 1 - #define UNAME_MACHINE "microblaze" +#define UNAME_MINIMUM_RELEASE "2.6.32" /* We use microblaze_reg_t to keep things similar to the kernel sources. */ typedef uint32_t microblaze_reg_t; diff --git a/linux-user/mips/syscall.h b/linux-user/mips/syscall.h index 9d437d918b..5bc56962a4 100644 --- a/linux-user/mips/syscall.h +++ b/linux-user/mips/syscall.h @@ -225,5 +225,6 @@ struct target_pt_regs { #define TARGET_QEMU_ESIGRETURN 255 #define UNAME_MACHINE "mips" +#define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h index 1710f766e2..a7f5a5802a 100644 --- a/linux-user/mips64/syscall.h +++ b/linux-user/mips64/syscall.h @@ -222,5 +222,6 @@ struct target_pt_regs { #define TARGET_QEMU_ESIGRETURN 255 #define UNAME_MACHINE "mips64" +#define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS diff --git a/linux-user/openrisc/syscall.h b/linux-user/openrisc/syscall.h index bdbb577fc3..c3b36da83c 100644 --- a/linux-user/openrisc/syscall.h +++ b/linux-user/openrisc/syscall.h @@ -22,3 +22,4 @@ struct target_pt_regs { }; #define UNAME_MACHINE "openrisc" +#define UNAME_MINIMUM_RELEASE "2.6.32" diff --git a/linux-user/ppc/syscall.h b/linux-user/ppc/syscall.h index ba36acbc33..6514c637a5 100644 --- a/linux-user/ppc/syscall.h +++ b/linux-user/ppc/syscall.h @@ -62,5 +62,6 @@ struct target_revectored_struct { #else #define UNAME_MACHINE "ppc" #endif +#define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS diff --git a/linux-user/s390x/syscall.h b/linux-user/s390x/syscall.h index e5ce30b667..aaad512d4d 100644 --- a/linux-user/s390x/syscall.h +++ b/linux-user/s390x/syscall.h @@ -21,5 +21,6 @@ struct target_pt_regs { }; #define UNAME_MACHINE "s390x" +#define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_CLONE_BACKWARDS2 diff --git a/linux-user/sh4/syscall.h b/linux-user/sh4/syscall.h index 014bf58fc3..ccd2216e38 100644 --- a/linux-user/sh4/syscall.h +++ b/linux-user/sh4/syscall.h @@ -10,3 +10,4 @@ struct target_pt_regs { }; #define UNAME_MACHINE "sh4" +#define UNAME_MINIMUM_RELEASE "2.6.32" diff --git a/linux-user/signal.c b/linux-user/signal.c index 04638e2ead..c8a1da0749 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1233,8 +1233,14 @@ static int target_restore_sigframe(CPUARMState *env, return 1; } - for (i = 0; i < 32 * 2; i++) { - __get_user(env->vfp.regs[i], &aux->fpsimd.vregs[i]); + for (i = 0; i < 32; i++) { +#ifdef TARGET_WORDS_BIGENDIAN + __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2 + 1]); + __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2]); +#else + __get_user(env->vfp.regs[i * 2], &aux->fpsimd.vregs[i * 2]); + __get_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]); +#endif } __get_user(fpsr, &aux->fpsimd.fpsr); vfp_set_fpsr(env, fpsr); @@ -1267,7 +1273,7 @@ static void target_setup_frame(int usig, struct target_sigaction *ka, CPUARMState *env) { struct target_rt_sigframe *frame; - abi_ulong frame_addr; + abi_ulong frame_addr, return_addr; frame_addr = get_sigframe(ka, env); if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) { @@ -1284,15 +1290,19 @@ static void target_setup_frame(int usig, struct target_sigaction *ka, __put_user(target_sigaltstack_used.ss_size, &frame->uc.tuc_stack.ss_size); target_setup_sigframe(frame, env, set); - /* mov x8,#__NR_rt_sigreturn; svc #0 */ - __put_user(0xd2801168, &frame->tramp[0]); - __put_user(0xd4000001, &frame->tramp[1]); + if (ka->sa_flags & TARGET_SA_RESTORER) { + return_addr = ka->sa_restorer; + } else { + /* mov x8,#__NR_rt_sigreturn; svc #0 */ + __put_user(0xd2801168, &frame->tramp[0]); + __put_user(0xd4000001, &frame->tramp[1]); + return_addr = frame_addr + offsetof(struct target_rt_sigframe, tramp); + } env->xregs[0] = usig; env->xregs[31] = frame_addr; env->xregs[29] = env->xregs[31] + offsetof(struct target_rt_sigframe, fp); env->pc = ka->_sa_handler; - env->xregs[30] = env->xregs[31] + - offsetof(struct target_rt_sigframe, tramp); + env->xregs[30] = return_addr; if (info) { if (copy_siginfo_to_user(&frame->info, info)) { goto give_sigsegv; diff --git a/linux-user/sparc/syscall.h b/linux-user/sparc/syscall.h index 4cd64bf41d..9549ea0a2f 100644 --- a/linux-user/sparc/syscall.h +++ b/linux-user/sparc/syscall.h @@ -7,6 +7,7 @@ struct target_pt_regs { }; #define UNAME_MACHINE "sun4" +#define UNAME_MINIMUM_RELEASE "2.6.32" /* SPARC kernels don't define this in their Kconfig, but they have the * same ABI as if they did, implemented by sparc-specific code which fishes diff --git a/linux-user/sparc64/syscall.h b/linux-user/sparc64/syscall.h index e60bf311c0..82b1680cb6 100644 --- a/linux-user/sparc64/syscall.h +++ b/linux-user/sparc64/syscall.h @@ -8,6 +8,7 @@ struct target_pt_regs { }; #define UNAME_MACHINE "sun4u" +#define UNAME_MINIMUM_RELEASE "2.6.32" /* SPARC kernels don't define this in their Kconfig, but they have the * same ABI as if they did, implemented by sparc-specific code which fishes diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 1407b7a546..e2c10cc0bd 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1904,23 +1904,16 @@ static abi_long do_connect(int sockfd, abi_ulong target_addr, return get_errno(connect(sockfd, addr, addrlen)); } -/* do_sendrecvmsg() Must return target values and target errnos. */ -static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, - int flags, int send) +/* do_sendrecvmsg_locked() Must return target values and target errnos. */ +static abi_long do_sendrecvmsg_locked(int fd, struct target_msghdr *msgp, + int flags, int send) { abi_long ret, len; - struct target_msghdr *msgp; struct msghdr msg; int count; struct iovec *vec; abi_ulong target_vec; - /* FIXME */ - if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE, - msgp, - target_msg, - send ? 1 : 0)) - return -TARGET_EFAULT; if (msgp->msg_name) { msg.msg_namelen = tswap32(msgp->msg_namelen); msg.msg_name = alloca(msg.msg_namelen); @@ -1975,10 +1968,75 @@ static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, out: unlock_iovec(vec, target_vec, count, !send); out2: + return ret; +} + +static abi_long do_sendrecvmsg(int fd, abi_ulong target_msg, + int flags, int send) +{ + abi_long ret; + struct target_msghdr *msgp; + + if (!lock_user_struct(send ? VERIFY_READ : VERIFY_WRITE, + msgp, + target_msg, + send ? 1 : 0)) { + return -TARGET_EFAULT; + } + ret = do_sendrecvmsg_locked(fd, msgp, flags, send); unlock_user_struct(msgp, target_msg, send ? 0 : 1); return ret; } +#ifdef TARGET_NR_sendmmsg +/* We don't rely on the C library to have sendmmsg/recvmmsg support, + * so it might not have this *mmsg-specific flag either. + */ +#ifndef MSG_WAITFORONE +#define MSG_WAITFORONE 0x10000 +#endif + +static abi_long do_sendrecvmmsg(int fd, abi_ulong target_msgvec, + unsigned int vlen, unsigned int flags, + int send) +{ + struct target_mmsghdr *mmsgp; + abi_long ret = 0; + int i; + + if (vlen > UIO_MAXIOV) { + vlen = UIO_MAXIOV; + } + + mmsgp = lock_user(VERIFY_WRITE, target_msgvec, sizeof(*mmsgp) * vlen, 1); + if (!mmsgp) { + return -TARGET_EFAULT; + } + + for (i = 0; i < vlen; i++) { + ret = do_sendrecvmsg_locked(fd, &mmsgp[i].msg_hdr, flags, send); + if (is_error(ret)) { + break; + } + mmsgp[i].msg_len = tswap32(ret); + /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */ + if (flags & MSG_WAITFORONE) { + flags |= MSG_DONTWAIT; + } + } + + unlock_user(mmsgp, target_msgvec, sizeof(*mmsgp) * i); + + /* Return number of datagrams sent if we sent any at all; + * otherwise return the error. + */ + if (i) { + return i; + } + return ret; +} +#endif + /* If we don't have a system accept4() then just call accept. * The callsites to do_accept4() will ensure that they don't * pass a non-zero flags argument in this config. @@ -4528,6 +4586,9 @@ static inline int tswapid(int id) { return tswap16(id); } + +#define put_user_id(x, gaddr) put_user_u16(x, gaddr) + #else /* !USE_UID16 */ static inline int high2lowuid(int uid) { @@ -4549,6 +4610,9 @@ static inline int tswapid(int id) { return tswap32(id); } + +#define put_user_id(x, gaddr) put_user_u32(x, gaddr) + #endif /* USE_UID16 */ void syscall_init(void) @@ -6121,11 +6185,17 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, puts = NULL; } ret = get_errno(sigtimedwait(&set, &uinfo, puts)); - if (!is_error(ret) && arg2) { - if (!(p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), 0))) - goto efault; - host_to_target_siginfo(p, &uinfo); - unlock_user(p, arg2, sizeof(target_siginfo_t)); + if (!is_error(ret)) { + if (arg2) { + p = lock_user(VERIFY_WRITE, arg2, sizeof(target_siginfo_t), + 0); + if (!p) { + goto efault; + } + host_to_target_siginfo(p, &uinfo); + unlock_user(p, arg2, sizeof(target_siginfo_t)); + } + ret = host_to_target_signal(ret); } } break; @@ -6710,6 +6780,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, ret = do_sendrecvmsg(arg1, arg2, arg3, 1); break; #endif +#ifdef TARGET_NR_sendmmsg + case TARGET_NR_sendmmsg: + ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 1); + break; + case TARGET_NR_recvmmsg: + ret = do_sendrecvmmsg(arg1, arg2, arg3, arg4, 0); + break; +#endif #ifdef TARGET_NR_sendto case TARGET_NR_sendto: ret = do_sendto(arg1, arg2, arg3, arg4, arg5, arg6); @@ -7805,9 +7883,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, uid_t ruid, euid, suid; ret = get_errno(getresuid(&ruid, &euid, &suid)); if (!is_error(ret)) { - if (put_user_u16(high2lowuid(ruid), arg1) - || put_user_u16(high2lowuid(euid), arg2) - || put_user_u16(high2lowuid(suid), arg3)) + if (put_user_id(high2lowuid(ruid), arg1) + || put_user_id(high2lowuid(euid), arg2) + || put_user_id(high2lowuid(suid), arg3)) goto efault; } } @@ -7826,9 +7904,9 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, gid_t rgid, egid, sgid; ret = get_errno(getresgid(&rgid, &egid, &sgid)); if (!is_error(ret)) { - if (put_user_u16(high2lowgid(rgid), arg1) - || put_user_u16(high2lowgid(egid), arg2) - || put_user_u16(high2lowgid(sgid), arg3)) + if (put_user_id(high2lowgid(rgid), arg1) + || put_user_id(high2lowgid(egid), arg2) + || put_user_id(high2lowgid(sgid), arg3)) goto efault; } } diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 3c8869e073..732c9e3dbb 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -53,7 +53,8 @@ #define TARGET_IOC_NRBITS 8 #define TARGET_IOC_TYPEBITS 8 -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \ +#if defined(TARGET_I386) || (defined(TARGET_ARM) && defined(TARGET_ABI32)) \ + || defined(TARGET_SPARC) \ || defined(TARGET_M68K) || defined(TARGET_SH4) || defined(TARGET_CRIS) /* 16 bit uid wrappers emulation */ #define USE_UID16 @@ -239,6 +240,10 @@ __target_cmsg_nxthdr (struct target_msghdr *__mhdr, struct target_cmsghdr *__cms return __cmsg; } +struct target_mmsghdr { + struct target_msghdr msg_hdr; /* Message header */ + unsigned int msg_len; /* Number of bytes transmitted */ +}; struct target_rusage { struct target_timeval ru_utime; /* user time used */ diff --git a/linux-user/unicore32/syscall.h b/linux-user/unicore32/syscall.h index 010cdd896e..f7e55254cf 100644 --- a/linux-user/unicore32/syscall.h +++ b/linux-user/unicore32/syscall.h @@ -51,5 +51,6 @@ struct target_pt_regs { #define UC32_SYSCALL_NR_set_tls (UC32_SYSCALL_ARCH_BASE + 5) #define UNAME_MACHINE "UniCore-II" +#define UNAME_MINIMUM_RELEASE "2.6.32" #endif /* __UC32_SYSCALL_H__ */ diff --git a/linux-user/x86_64/syscall.h b/linux-user/x86_64/syscall.h index 81314cfae6..e03b5a0cfc 100644 --- a/linux-user/x86_64/syscall.h +++ b/linux-user/x86_64/syscall.h @@ -91,6 +91,7 @@ struct target_msqid64_ds { }; #define UNAME_MACHINE "x86_64" +#define UNAME_MINIMUM_RELEASE "2.6.32" #define TARGET_ARCH_SET_GS 0x1001 #define TARGET_ARCH_SET_FS 0x1002 @@ -1562,7 +1562,7 @@ static FlatRange *flatview_lookup(FlatView *view, AddrRange addr) bool memory_region_present(MemoryRegion *parent, hwaddr addr) { MemoryRegion *mr = memory_region_find(parent, addr, 1).mr; - if (!mr) { + if (!mr || (mr == parent)) { return false; } memory_region_unref(mr); diff --git a/migration.c b/migration.c index 14235b280a..00f465ea46 100644 --- a/migration.c +++ b/migration.c @@ -695,6 +695,6 @@ void migrate_fd_connect(MigrationState *s) /* Notify before starting migration thread */ notifier_list_notify(&migration_state_notifiers, s); - qemu_thread_create(&s->thread, migration_thread, s, + qemu_thread_create(&s->thread, "migration", migration_thread, s, QEMU_THREAD_JOINABLE); } diff --git a/pc-bios/README b/pc-bios/README index 5914200b23..2bb6357ea6 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -12,7 +12,7 @@ 1275-1994 (referred to as Open Firmware) compliant firmware. The included images for PowerPC (for 32 and 64 bit PPC CPUs), Sparc32 (including QEMU,tcx.bin and QEMU,cgthree.bin) and Sparc64 are built - from OpenBIOS SVN revision 1246. + from OpenBIOS SVN revision 1280. - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc Binary files differindex f4a3a396c4..8a213894be 100644 --- a/pc-bios/openbios-ppc +++ b/pc-bios/openbios-ppc diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 Binary files differindex bb7cdfb4ec..d4d00e501f 100644 --- a/pc-bios/openbios-sparc32 +++ b/pc-bios/openbios-sparc32 diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 Binary files differindex 46b4fddd08..4182052d65 100644 --- a/pc-bios/openbios-sparc64 +++ b/pc-bios/openbios-sparc64 diff --git a/qemu-options.hx b/qemu-options.hx index 56e5fdf1e0..068da2df09 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -328,9 +328,11 @@ possible drivers and properties, use @code{-device help} and ETEXI DEF("name", HAS_ARG, QEMU_OPTION_name, - "-name string1[,process=string2]\n" + "-name string1[,process=string2][,debug-threads=on|off]\n" " set the name of the guest\n" - " string1 sets the window title and string2 the process name (on Linux)\n", + " string1 sets the window title and string2 the process name (on Linux)\n" + " When debug-threads is enabled, individual threads are given a separate name (on Linux)\n" + " NOTE: The thread names are for debugging and not a stable API.\n", QEMU_ARCH_ALL) STEXI @item -name @var{name} @@ -339,6 +341,7 @@ Sets the @var{name} of the guest. This name will be displayed in the SDL window caption. The @var{name} will also be used for the VNC server. Also optionally set the top visible process name in Linux. +Naming of individual threads can also be enabled on Linux to aid debugging. ETEXI DEF("uuid", HAS_ARG, QEMU_OPTION_uuid, diff --git a/roms/openbios b/roms/openbios -Subproject 888126272f92294b0da45158393f1b862742cf6 +Subproject 1ac3fb92c109f5545d373a0576b87750c53cce1 diff --git a/tests/acpi-test-data/pc/DSDT b/tests/acpi-test-data/pc/DSDT Binary files differindex fbf1c3e6e8..8b14a5f6f2 100644 --- a/tests/acpi-test-data/pc/DSDT +++ b/tests/acpi-test-data/pc/DSDT diff --git a/tests/acpi-test-data/pc/SSDT b/tests/acpi-test-data/pc/SSDT Binary files differindex a51c68e21b..c1a4589db0 100644 --- a/tests/acpi-test-data/pc/SSDT +++ b/tests/acpi-test-data/pc/SSDT diff --git a/tests/acpi-test-data/q35/DSDT b/tests/acpi-test-data/q35/DSDT Binary files differindex 5086b839a6..a76ea9a418 100644 --- a/tests/acpi-test-data/q35/DSDT +++ b/tests/acpi-test-data/q35/DSDT diff --git a/tests/acpi-test-data/q35/SSDT b/tests/acpi-test-data/q35/SSDT Binary files differindex 9c6cad8b0b..9915dbe5b1 100644 --- a/tests/acpi-test-data/q35/SSDT +++ b/tests/acpi-test-data/q35/SSDT diff --git a/tests/acpi-test.c b/tests/acpi-test.c index 31f5359787..185309a241 100644 --- a/tests/acpi-test.c +++ b/tests/acpi-test.c @@ -34,7 +34,7 @@ typedef struct { gchar *asl; /* asl code generated from aml */ gsize asl_len; gchar *asl_file; - bool asl_file_retain; /* do not delete the temp asl */ + bool tmp_files_retain; /* do not delete the temp asl/aml */ } QEMU_PACKED AcpiSdtTable; typedef struct { @@ -153,7 +153,8 @@ static void free_test_data(test_data *data) g_free(temp->aml); } if (temp->aml_file) { - if (g_strstr_len(temp->aml_file, -1, "aml-")) { + if (!temp->tmp_files_retain && + g_strstr_len(temp->aml_file, -1, "aml-")) { unlink(temp->aml_file); } g_free(temp->aml_file); @@ -162,7 +163,7 @@ static void free_test_data(test_data *data) g_free(temp->asl); } if (temp->asl_file) { - if (!temp->asl_file_retain) { + if (!temp->tmp_files_retain) { unlink(temp->asl_file); } g_free(temp->asl_file); @@ -410,7 +411,7 @@ static bool compare_signature(AcpiSdtTable *sdt, uint32_t signature) return sdt->header.signature == signature; } -static void load_asl(GArray *sdts, AcpiSdtTable *sdt) +static bool load_asl(GArray *sdts, AcpiSdtTable *sdt) { AcpiSdtTable *temp; GError *error = NULL; @@ -439,18 +440,22 @@ static void load_asl(GArray *sdts, AcpiSdtTable *sdt) g_string_append_printf(command_line, "-d %s", sdt->aml_file); /* pass 'out' and 'out_err' in order to be redirected */ - g_spawn_command_line_sync(command_line->str, &out, &out_err, NULL, &error); + ret = g_spawn_command_line_sync(command_line->str, &out, &out_err, NULL, &error); g_assert_no_error(error); - ret = g_file_get_contents(sdt->asl_file, (gchar **)&sdt->asl, - &sdt->asl_len, &error); - g_assert(ret); - g_assert_no_error(error); - g_assert(sdt->asl_len); + if (ret) { + ret = g_file_get_contents(sdt->asl_file, (gchar **)&sdt->asl, + &sdt->asl_len, &error); + g_assert(ret); + g_assert_no_error(error); + g_assert(sdt->asl_len); + } g_free(out); g_free(out_err); g_string_free(command_line, true); + + return !ret; } #define COMMENT_END "*/" @@ -517,6 +522,7 @@ static void test_acpi_asl(test_data *data) int i; AcpiSdtTable *sdt, *exp_sdt; test_data exp_data; + gboolean exp_err, err; memset(&exp_data, 0, sizeof(exp_data)); exp_data.tables = load_expected_aml(data); @@ -527,20 +533,24 @@ static void test_acpi_asl(test_data *data) sdt = &g_array_index(data->tables, AcpiSdtTable, i); exp_sdt = &g_array_index(exp_data.tables, AcpiSdtTable, i); - load_asl(data->tables, sdt); + err = load_asl(data->tables, sdt); asl = normalize_asl(sdt->asl); - load_asl(exp_data.tables, exp_sdt); + exp_err = load_asl(exp_data.tables, exp_sdt); exp_asl = normalize_asl(exp_sdt->asl); + /* TODO: check for warnings */ + g_assert(!err || exp_err); + if (g_strcmp0(asl->str, exp_asl->str)) { - sdt->asl_file_retain = true; - exp_sdt->asl_file_retain = true; + sdt->tmp_files_retain = true; + exp_sdt->tmp_files_retain = true; fprintf(stderr, "acpi-test: Warning! %.4s mismatch. " - "Orig asl: %s, expected asl %s.\n", + "Actual [asl:%s, aml:%s], Expected [asl:%s, aml:%s].\n", (gchar *)&exp_sdt->header.signature, - sdt->asl_file, exp_sdt->asl_file); + sdt->asl_file, sdt->aml_file, + exp_sdt->asl_file, exp_sdt->aml_file); } g_string_free(asl, true); g_string_free(exp_asl, true); diff --git a/thread-pool.c b/thread-pool.c index 3735fd34bc..fbdd3ffa3a 100644 --- a/thread-pool.c +++ b/thread-pool.c @@ -140,7 +140,7 @@ static void do_spawn_thread(ThreadPool *pool) pool->new_threads--; pool->pending_threads++; - qemu_thread_create(&t, worker_thread, pool, QEMU_THREAD_DETACHED); + qemu_thread_create(&t, "worker", worker_thread, pool, QEMU_THREAD_DETACHED); } static void spawn_thread_bh_fn(void *opaque) diff --git a/ui/input-legacy.c b/ui/input-legacy.c index f38984b192..7dc486b8ac 100644 --- a/ui/input-legacy.c +++ b/ui/input-legacy.c @@ -359,6 +359,20 @@ static void legacy_mouse_event(DeviceState *dev, QemuConsole *src, } else { s->buttons &= ~bmap[evt->btn->button]; } + if (evt->btn->down && evt->btn->button == INPUT_BUTTON_WHEEL_UP) { + s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque, + s->axis[INPUT_AXIS_X], + s->axis[INPUT_AXIS_Y], + -1, + s->buttons); + } + if (evt->btn->down && evt->btn->button == INPUT_BUTTON_WHEEL_DOWN) { + s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque, + s->axis[INPUT_AXIS_X], + s->axis[INPUT_AXIS_Y], + 1, + s->buttons); + } break; case INPUT_EVENT_KIND_ABS: s->axis[evt->abs->axis] = evt->abs->value; @@ -455,13 +455,17 @@ static void sdl_send_mouse_event(int dx, int dy, int x, int y, int state) real_screen->w); qemu_input_queue_abs(dcl->con, INPUT_AXIS_Y, y, real_screen->h); - } else if (guest_cursor) { - x -= guest_x; - y -= guest_y; - guest_x += x; - guest_y += y; - qemu_input_queue_rel(dcl->con, INPUT_AXIS_X, x); - qemu_input_queue_rel(dcl->con, INPUT_AXIS_Y, y); + } else { + if (guest_cursor) { + x -= guest_x; + y -= guest_y; + guest_x += x; + guest_y += y; + dx = x; + dy = y; + } + qemu_input_queue_rel(dcl->con, INPUT_AXIS_X, dx); + qemu_input_queue_rel(dcl->con, INPUT_AXIS_Y, dy); } qemu_input_event_sync(); } diff --git a/ui/spice-display.c b/ui/spice-display.c index 9bb42f1461..e28698c6b6 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -354,6 +354,7 @@ void qemu_spice_display_switch(SimpleSpiceDisplay *ssd, DisplaySurface *surface) { SimpleSpiceUpdate *update; + bool need_destroy; dprint(1, "%s/%d:\n", __func__, ssd->qxl.id); @@ -366,14 +367,19 @@ void qemu_spice_display_switch(SimpleSpiceDisplay *ssd, } qemu_mutex_lock(&ssd->lock); + need_destroy = (ssd->ds != NULL); ssd->ds = surface; while ((update = QTAILQ_FIRST(&ssd->updates)) != NULL) { QTAILQ_REMOVE(&ssd->updates, update, next); qemu_spice_destroy_update(ssd, update); } qemu_mutex_unlock(&ssd->lock); - qemu_spice_destroy_host_primary(ssd); - qemu_spice_create_host_primary(ssd); + if (need_destroy) { + qemu_spice_destroy_host_primary(ssd); + } + if (ssd->ds) { + qemu_spice_create_host_primary(ssd); + } memset(&ssd->dirty, 0, sizeof(ssd->dirty)); ssd->notify++; @@ -537,10 +543,29 @@ static void interface_set_client_capabilities(QXLInstance *sin, } static int interface_client_monitors_config(QXLInstance *sin, - VDAgentMonitorsConfig *monitors_config) + VDAgentMonitorsConfig *mc) { - dprint(3, "%s:\n", __func__); - return 0; /* == not supported by guest */ + SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); + QemuUIInfo info; + int rc; + + /* + * FIXME: multihead is tricky due to the way + * spice has multihead implemented. + */ + memset(&info, 0, sizeof(info)); + if (mc->num_of_monitors > 0) { + info.width = mc->monitors[0].width; + info.height = mc->monitors[0].height; + } + rc = dpy_set_ui_info(ssd->dcl.con, &info); + dprint(1, "%s/%d: size %dx%d, rc %d <--- ==========================\n", + __func__, ssd->qxl.id, info.width, info.height, rc); + if (rc != 0) { + return 0; /* == not supported by guest */ + } else { + return 1; + } } static const QXLInterface dpy_interface = { @@ -610,8 +635,6 @@ static void qemu_spice_display_init_one(QemuConsole *con) ssd->dcl.ops = &display_listener_ops; ssd->dcl.con = con; register_displaychangelistener(&ssd->dcl); - - qemu_spice_create_host_primary(ssd); } void qemu_spice_display_init(void) diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c index e6966aebc3..59b59c0c79 100644 --- a/ui/vnc-enc-tight.c +++ b/ui/vnc-enc-tight.c @@ -330,7 +330,7 @@ tight_detect_smooth_image(VncState *vs, int w, int h) } else { errors = tight_detect_smooth_image16(vs, w, h); } - if (quality != -1) { + if (quality != (uint8_t)-1) { return (errors < tight_conf[quality].jpeg_threshold); } return (errors < tight_conf[compression].gradient_threshold); diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c index 2d3fce8155..68f3d773d9 100644 --- a/ui/vnc-jobs.c +++ b/ui/vnc-jobs.c @@ -252,6 +252,8 @@ static int vnc_worker_thread_loop(VncJobQueue *queue) if (job->vs->csock == -1) { vnc_unlock_display(job->vs->vd); + /* Copy persistent encoding data */ + vnc_async_encoding_end(job->vs, &vs); goto disconnected; } @@ -278,6 +280,9 @@ static int vnc_worker_thread_loop(VncJobQueue *queue) vnc_async_encoding_end(job->vs, &vs); qemu_bh_schedule(job->vs->bh); + } else { + /* Copy persistent encoding data */ + vnc_async_encoding_end(job->vs, &vs); } vnc_unlock_output(job->vs); @@ -333,7 +338,8 @@ void vnc_start_worker_thread(void) return ; q = vnc_queue_init(); - qemu_thread_create(&q->thread, vnc_worker_thread, q, QEMU_THREAD_DETACHED); + qemu_thread_create(&q->thread, "vnc_worker", vnc_worker_thread, q, + QEMU_THREAD_DETACHED); queue = q; /* Set global queue */ } @@ -417,8 +417,7 @@ out_error: 3) resolutions > 1024 */ -static int vnc_update_client(VncState *vs, int has_dirty); -static int vnc_update_client_sync(VncState *vs, int has_dirty); +static int vnc_update_client(VncState *vs, int has_dirty, bool sync); static void vnc_disconnect_start(VncState *vs); static void vnc_colordepth(VncState *vs); @@ -431,29 +430,25 @@ static int vnc_refresh_server_surface(VncDisplay *vd); static void vnc_dpy_update(DisplayChangeListener *dcl, int x, int y, int w, int h) { - int i; VncDisplay *vd = container_of(dcl, VncDisplay, dcl); struct VncSurface *s = &vd->guest; int width = surface_width(vd->ds); int height = surface_height(vd->ds); - h += y; - - /* round x down to ensure the loop only spans one 16-pixel block per, - iteration. otherwise, if (x % 16) != 0, the last iteration may span - two 16-pixel blocks but we only mark the first as dirty - */ - w += (x % 16); - x -= (x % 16); + /* this is needed this to ensure we updated all affected + * blocks if x % VNC_DIRTY_PIXELS_PER_BIT != 0 */ + w += (x % VNC_DIRTY_PIXELS_PER_BIT); + x -= (x % VNC_DIRTY_PIXELS_PER_BIT); x = MIN(x, width); y = MIN(y, height); w = MIN(x + w, width) - x; - h = MIN(h, height); + h = MIN(y + h, height); - for (; y < h; y++) - for (i = 0; i < w; i += 16) - set_bit((x + i) / 16, s->dirty[y]); + for (; y < h; y++) { + bitmap_set(s->dirty[y], x / VNC_DIRTY_PIXELS_PER_BIT, + DIV_ROUND_UP(w, VNC_DIRTY_PIXELS_PER_BIT)); + } } void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h, @@ -571,6 +566,15 @@ void *vnc_server_fb_ptr(VncDisplay *vd, int x, int y) ptr += x * VNC_SERVER_FB_BYTES; return ptr; } +/* this sets only the visible pixels of a dirty bitmap */ +#define VNC_SET_VISIBLE_PIXELS_DIRTY(bitmap, w, h) {\ + int y;\ + memset(bitmap, 0x00, sizeof(bitmap));\ + for (y = 0; y < h; y++) {\ + bitmap_set(bitmap[y], 0,\ + DIV_ROUND_UP(w, VNC_DIRTY_PIXELS_PER_BIT));\ + } \ + } static void vnc_dpy_switch(DisplayChangeListener *dcl, DisplaySurface *surface) @@ -596,7 +600,9 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl, qemu_pixman_image_unref(vd->guest.fb); vd->guest.fb = pixman_image_ref(surface->image); vd->guest.format = surface->format; - memset(vd->guest.dirty, 0xFF, sizeof(vd->guest.dirty)); + VNC_SET_VISIBLE_PIXELS_DIRTY(vd->guest.dirty, + surface_width(vd->ds), + surface_height(vd->ds)); QTAILQ_FOREACH(vs, &vd->clients, next) { vnc_colordepth(vs); @@ -604,7 +610,9 @@ static void vnc_dpy_switch(DisplayChangeListener *dcl, if (vs->vd->cursor) { vnc_cursor_define(vs); } - memset(vs->dirty, 0xFF, sizeof(vs->dirty)); + VNC_SET_VISIBLE_PIXELS_DIRTY(vs->dirty, + surface_width(vd->ds), + surface_height(vd->ds)); } } @@ -751,7 +759,7 @@ static void vnc_dpy_copy(DisplayChangeListener *dcl, QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) { if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) { vs->force_update = 1; - vnc_update_client_sync(vs, 1); + vnc_update_client(vs, 1, true); /* vs might be free()ed here */ } } @@ -770,11 +778,12 @@ static void vnc_dpy_copy(DisplayChangeListener *dcl, y = dst_y + h - 1; inc = -1; } - w_lim = w - (16 - (dst_x % 16)); - if (w_lim < 0) + w_lim = w - (VNC_DIRTY_PIXELS_PER_BIT - (dst_x % VNC_DIRTY_PIXELS_PER_BIT)); + if (w_lim < 0) { w_lim = w; - else - w_lim = w - (w_lim % 16); + } else { + w_lim = w - (w_lim % VNC_DIRTY_PIXELS_PER_BIT); + } for (i = 0; i < h; i++) { for (x = 0; x <= w_lim; x += s, src_row += cmp_bytes, dst_row += cmp_bytes) { @@ -782,10 +791,11 @@ static void vnc_dpy_copy(DisplayChangeListener *dcl, if ((s = w - w_lim) == 0) break; } else if (!x) { - s = (16 - (dst_x % 16)); + s = (VNC_DIRTY_PIXELS_PER_BIT - + (dst_x % VNC_DIRTY_PIXELS_PER_BIT)); s = MIN(s, w_lim); } else { - s = 16; + s = VNC_DIRTY_PIXELS_PER_BIT; } cmp_bytes = s * VNC_SERVER_FB_BYTES; if (memcmp(src_row, dst_row, cmp_bytes) == 0) @@ -793,7 +803,8 @@ static void vnc_dpy_copy(DisplayChangeListener *dcl, memmove(dst_row, src_row, cmp_bytes); QTAILQ_FOREACH(vs, &vd->clients, next) { if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) { - set_bit(((x + dst_x) / 16), vs->dirty[y]); + set_bit(((x + dst_x) / VNC_DIRTY_PIXELS_PER_BIT), + vs->dirty[y]); } } } @@ -862,35 +873,24 @@ static int find_and_clear_dirty_height(struct VncState *vs, int h; for (h = 1; h < (height - y); h++) { - int tmp_x; if (!test_bit(last_x, vs->dirty[y + h])) { break; } - for (tmp_x = last_x; tmp_x < x; tmp_x++) { - clear_bit(tmp_x, vs->dirty[y + h]); - } + bitmap_clear(vs->dirty[y + h], last_x, x - last_x); } return h; } -static int vnc_update_client_sync(VncState *vs, int has_dirty) -{ - int ret = vnc_update_client(vs, has_dirty); - vnc_jobs_join(vs); - return ret; -} - -static int vnc_update_client(VncState *vs, int has_dirty) +static int vnc_update_client(VncState *vs, int has_dirty, bool sync) { if (vs->need_update && vs->csock != -1) { VncDisplay *vd = vs->vd; VncJob *job; int y; - int width, height; + int height; int n = 0; - if (vs->output.offset && !vs->audio_cap && !vs->force_update) /* kernel send buffers are full -> drop frames to throttle */ return 0; @@ -906,33 +906,27 @@ static int vnc_update_client(VncState *vs, int has_dirty) */ job = vnc_job_new(vs); - width = MIN(pixman_image_get_width(vd->server), vs->client_width); height = MIN(pixman_image_get_height(vd->server), vs->client_height); - for (y = 0; y < height; y++) { - int x; - int last_x = -1; - for (x = 0; x < width / 16; x++) { - if (test_and_clear_bit(x, vs->dirty[y])) { - if (last_x == -1) { - last_x = x; - } - } else { - if (last_x != -1) { - int h = find_and_clear_dirty_height(vs, y, last_x, x, - height); - - n += vnc_job_add_rect(job, last_x * 16, y, - (x - last_x) * 16, h); - } - last_x = -1; - } - } - if (last_x != -1) { - int h = find_and_clear_dirty_height(vs, y, last_x, x, height); - n += vnc_job_add_rect(job, last_x * 16, y, - (x - last_x) * 16, h); + y = 0; + for (;;) { + int x, h; + unsigned long x2; + unsigned long offset = find_next_bit((unsigned long *) &vs->dirty, + height * VNC_DIRTY_BPL(vs), + y * VNC_DIRTY_BPL(vs)); + if (offset == height * VNC_DIRTY_BPL(vs)) { + /* no more dirty bits */ + break; } + y = offset / VNC_DIRTY_BPL(vs); + x = offset % VNC_DIRTY_BPL(vs); + x2 = find_next_zero_bit((unsigned long *) &vs->dirty[y], + VNC_DIRTY_BPL(vs), x); + bitmap_clear(vs->dirty[y], x, x2 - x); + h = find_and_clear_dirty_height(vs, y, x, x2, height); + n += vnc_job_add_rect(job, x * VNC_DIRTY_PIXELS_PER_BIT, y, + (x2 - x) * VNC_DIRTY_PIXELS_PER_BIT, h); } vnc_job_push(job); @@ -940,8 +934,11 @@ static int vnc_update_client(VncState *vs, int has_dirty) return n; } - if (vs->csock == -1) + if (vs->csock == -1) { vnc_disconnect_finish(vs); + } else if (sync) { + vnc_jobs_join(vs); + } return 0; } @@ -1846,7 +1843,7 @@ static void framebuffer_update_request(VncState *vs, int incremental, int w, int h) { int i; - const size_t width = surface_width(vs->vd->ds) / 16; + const size_t width = surface_width(vs->vd->ds) / VNC_DIRTY_PIXELS_PER_BIT; const size_t height = surface_height(vs->vd->ds); if (y_position > height) { @@ -2548,7 +2545,9 @@ static int vnc_refresh_lossy_rect(VncDisplay *vd, int x, int y) vs->lossy_rect[sty][stx] = 0; for (j = 0; j < VNC_STAT_RECT; ++j) { - bitmap_set(vs->dirty[y + j], x / 16, VNC_STAT_RECT / 16); + bitmap_set(vs->dirty[y + j], + x / VNC_DIRTY_PIXELS_PER_BIT, + VNC_STAT_RECT / VNC_DIRTY_PIXELS_PER_BIT); } has_dirty++; } @@ -2652,8 +2651,8 @@ static int vnc_refresh_server_surface(VncDisplay *vd) int width = pixman_image_get_width(vd->guest.fb); int height = pixman_image_get_height(vd->guest.fb); int y; - uint8_t *guest_row; - uint8_t *server_row; + uint8_t *guest_row0 = NULL, *server_row0; + int guest_stride = 0, server_stride; int cmp_bytes; VncState *vs; int has_dirty = 0; @@ -2671,47 +2670,64 @@ static int vnc_refresh_server_surface(VncDisplay *vd) * Check and copy modified bits from guest to server surface. * Update server dirty map. */ - cmp_bytes = 64; + cmp_bytes = VNC_DIRTY_PIXELS_PER_BIT * VNC_SERVER_FB_BYTES; if (cmp_bytes > vnc_server_fb_stride(vd)) { cmp_bytes = vnc_server_fb_stride(vd); } if (vd->guest.format != VNC_SERVER_FB_FORMAT) { int width = pixman_image_get_width(vd->server); tmpbuf = qemu_pixman_linebuf_create(VNC_SERVER_FB_FORMAT, width); - } - guest_row = (uint8_t *)pixman_image_get_data(vd->guest.fb); - server_row = (uint8_t *)pixman_image_get_data(vd->server); - for (y = 0; y < height; y++) { - if (!bitmap_empty(vd->guest.dirty[y], VNC_DIRTY_BITS)) { - int x; - uint8_t *guest_ptr; - uint8_t *server_ptr; - - if (vd->guest.format != VNC_SERVER_FB_FORMAT) { - qemu_pixman_linebuf_fill(tmpbuf, vd->guest.fb, width, 0, y); - guest_ptr = (uint8_t *)pixman_image_get_data(tmpbuf); - } else { - guest_ptr = guest_row; - } - server_ptr = server_row; + } else { + guest_row0 = (uint8_t *)pixman_image_get_data(vd->guest.fb); + guest_stride = pixman_image_get_stride(vd->guest.fb); + } + server_row0 = (uint8_t *)pixman_image_get_data(vd->server); + server_stride = pixman_image_get_stride(vd->server); + + y = 0; + for (;;) { + int x; + uint8_t *guest_ptr, *server_ptr; + unsigned long offset = find_next_bit((unsigned long *) &vd->guest.dirty, + height * VNC_DIRTY_BPL(&vd->guest), + y * VNC_DIRTY_BPL(&vd->guest)); + if (offset == height * VNC_DIRTY_BPL(&vd->guest)) { + /* no more dirty bits */ + break; + } + y = offset / VNC_DIRTY_BPL(&vd->guest); + x = offset % VNC_DIRTY_BPL(&vd->guest); - for (x = 0; x + 15 < width; - x += 16, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) { - if (!test_and_clear_bit((x / 16), vd->guest.dirty[y])) - continue; - if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0) - continue; - memcpy(server_ptr, guest_ptr, cmp_bytes); - if (!vd->non_adaptive) - vnc_rect_updated(vd, x, y, &tv); - QTAILQ_FOREACH(vs, &vd->clients, next) { - set_bit((x / 16), vs->dirty[y]); - } - has_dirty++; + server_ptr = server_row0 + y * server_stride + x * cmp_bytes; + + if (vd->guest.format != VNC_SERVER_FB_FORMAT) { + qemu_pixman_linebuf_fill(tmpbuf, vd->guest.fb, width, 0, y); + guest_ptr = (uint8_t *)pixman_image_get_data(tmpbuf); + } else { + guest_ptr = guest_row0 + y * guest_stride; + } + guest_ptr += x * cmp_bytes; + + for (; x < DIV_ROUND_UP(width, VNC_DIRTY_PIXELS_PER_BIT); + x++, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) { + if (!test_and_clear_bit(x, vd->guest.dirty[y])) { + continue; + } + if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0) { + continue; + } + memcpy(server_ptr, guest_ptr, cmp_bytes); + if (!vd->non_adaptive) { + vnc_rect_updated(vd, x * VNC_DIRTY_PIXELS_PER_BIT, + y, &tv); } + QTAILQ_FOREACH(vs, &vd->clients, next) { + set_bit(x, vs->dirty[y]); + } + has_dirty++; } - guest_row += pixman_image_get_stride(vd->guest.fb); - server_row += pixman_image_get_stride(vd->server); + + y++; } qemu_pixman_image_unref(tmpbuf); return has_dirty; @@ -2734,7 +2750,7 @@ static void vnc_refresh(DisplayChangeListener *dcl) vnc_unlock_display(vd); QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) { - rects += vnc_update_client(vs, has_dirty); + rects += vnc_update_client(vs, has_dirty, false); /* vs might be free()ed here */ } @@ -3134,7 +3150,9 @@ void vnc_display_open(DisplayState *ds, const char *display, Error **errp) acl = 1; #endif } else if (strncmp(options, "lossy", 5) == 0) { +#ifdef CONFIG_VNC_JPEG vs->lossy = true; +#endif } else if (strncmp(options, "non-adaptive", 12) == 0) { vs->non_adaptive = true; } else if (strncmp(options, "share=", 6) == 0) { @@ -3151,6 +3169,13 @@ void vnc_display_open(DisplayState *ds, const char *display, Error **errp) } } + /* adaptive updates are only used with tight encoding and + * if lossy updates are enabled so we can disable all the + * calculations otherwise */ + if (!vs->lossy) { + vs->non_adaptive = true; + } + #ifdef CONFIG_VNC_TLS if (acl && x509 && vs->tls.x509verify) { if (!(vs->tls.acl = qemu_acl_init("vnc.x509dname"))) { @@ -81,8 +81,16 @@ typedef void VncSendHextileTile(VncState *vs, #define VNC_MAX_WIDTH 2560 #define VNC_MAX_HEIGHT 2048 +/* VNC_DIRTY_PIXELS_PER_BIT is the number of dirty pixels represented + * by one bit in the dirty bitmap */ +#define VNC_DIRTY_PIXELS_PER_BIT 16 + /* VNC_DIRTY_BITS is the number of bits in the dirty bitmap. */ -#define VNC_DIRTY_BITS (VNC_MAX_WIDTH / 16) +#define VNC_DIRTY_BITS (VNC_MAX_WIDTH / VNC_DIRTY_PIXELS_PER_BIT) + +/* VNC_DIRTY_BPL (BPL = bits per line) might be greater than + * VNC_DIRTY_BITS due to alignment */ +#define VNC_DIRTY_BPL(x) (sizeof((x)->dirty) / VNC_MAX_HEIGHT * BITS_PER_BYTE) #define VNC_STAT_RECT 64 #define VNC_STAT_COLS (VNC_MAX_WIDTH / VNC_STAT_RECT) diff --git a/util/compatfd.c b/util/compatfd.c index 430a41c855..341ada638f 100644 --- a/util/compatfd.c +++ b/util/compatfd.c @@ -88,7 +88,8 @@ static int qemu_signalfd_compat(const sigset_t *mask) memcpy(&info->mask, mask, sizeof(*mask)); info->fd = fds[1]; - qemu_thread_create(&thread, sigwait_compat, info, QEMU_THREAD_DETACHED); + qemu_thread_create(&thread, "signalfd_compat", sigwait_compat, info, + QEMU_THREAD_DETACHED); return fds[0]; } diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c index 37dd298631..45113b464d 100644 --- a/util/qemu-thread-posix.c +++ b/util/qemu-thread-posix.c @@ -27,6 +27,13 @@ #include "qemu/thread.h" #include "qemu/atomic.h" +static bool name_threads; + +void qemu_thread_naming(bool enable) +{ + name_threads = enable; +} + static void error_exit(int err, const char *msg) { fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err)); @@ -387,8 +394,7 @@ void qemu_event_wait(QemuEvent *ev) } } - -void qemu_thread_create(QemuThread *thread, +void qemu_thread_create(QemuThread *thread, const char *name, void *(*start_routine)(void*), void *arg, int mode) { @@ -414,6 +420,12 @@ void qemu_thread_create(QemuThread *thread, if (err) error_exit(err, __func__); +#ifdef _GNU_SOURCE + if (name_threads) { + pthread_setname_np(thread->thread, name); + } +#endif + pthread_sigmask(SIG_SETMASK, &oldset, NULL); pthread_attr_destroy(&attr); diff --git a/util/qemu-thread-win32.c b/util/qemu-thread-win32.c index 27a5217769..b9c957b6a0 100644 --- a/util/qemu-thread-win32.c +++ b/util/qemu-thread-win32.c @@ -16,6 +16,14 @@ #include <assert.h> #include <limits.h> +static bool name_threads; + +void qemu_thread_naming(bool enable) +{ + /* But note we don't actually name them on Windows yet */ + name_threads = enable; +} + static void error_exit(int err, const char *msg) { char *pstr; @@ -325,7 +333,7 @@ void *qemu_thread_join(QemuThread *thread) return ret; } -void qemu_thread_create(QemuThread *thread, +void qemu_thread_create(QemuThread *thread, const char *name, void *(*start_routine)(void *), void *arg, int mode) { @@ -479,6 +479,33 @@ static QemuOptsList qemu_msg_opts = { }, }; +static QemuOptsList qemu_name_opts = { + .name = "name", + .implied_opt_name = "guest", + .merge_lists = true, + .head = QTAILQ_HEAD_INITIALIZER(qemu_name_opts.head), + .desc = { + { + .name = "guest", + .type = QEMU_OPT_STRING, + .help = "Sets the name of the guest.\n" + "This name will be displayed in the SDL window caption.\n" + "The name will also be used for the VNC server", + }, { + .name = "process", + .type = QEMU_OPT_STRING, + .help = "Sets the name of the QEMU process, as shown in top etc", + }, { + .name = "debug-threads", + .type = QEMU_OPT_BOOL, + .help = "When enabled, name the individual threads; defaults off.\n" + "NOTE: The thread names are for debugging and not a\n" + "stable API.", + }, + { /* End of list */ } + }, +}; + /** * Get machine options * @@ -929,6 +956,21 @@ static int parse_sandbox(QemuOpts *opts, void *opaque) return 0; } +static void parse_name(QemuOpts *opts) +{ + const char *proc_name; + + if (qemu_opt_get(opts, "debug-threads")) { + qemu_thread_naming(qemu_opt_get_bool(opts, "debug-threads", false)); + } + qemu_name = qemu_opt_get(opts, "guest"); + + proc_name = qemu_opt_get(opts, "process"); + if (proc_name) { + os_set_proc_name(proc_name); + } +} + bool usb_enabled(bool default_usb) { return qemu_opt_get_bool(qemu_get_machine_opts(), "usb", default_usb); @@ -2889,6 +2931,7 @@ int main(int argc, char **argv, char **envp) qemu_add_opts(&qemu_tpmdev_opts); qemu_add_opts(&qemu_realtime_opts); qemu_add_opts(&qemu_msg_opts); + qemu_add_opts(&qemu_name_opts); runstate_init(); @@ -3634,19 +3677,11 @@ int main(int argc, char **argv, char **envp) "is no longer supported.\n"); break; case QEMU_OPTION_name: - qemu_name = g_strdup(optarg); - { - char *p = strchr(qemu_name, ','); - if (p != NULL) { - *p++ = 0; - if (strncmp(p, "process=", 8)) { - fprintf(stderr, "Unknown subargument %s to -name\n", p); - exit(1); - } - p += 8; - os_set_proc_name(p); - } - } + opts = qemu_opts_parse(qemu_find_opts("name"), optarg, 1); + if (!opts) { + exit(1); + } + parse_name(opts); break; case QEMU_OPTION_prom_env: if (nb_prom_envs >= MAX_PROM_ENVS) { |