summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/system/ppc/embedded.rst10
-rw-r--r--docs/system/ppc/powermac.rst34
-rw-r--r--docs/system/ppc/powernv.rst193
-rw-r--r--docs/system/ppc/prep.rst18
-rw-r--r--docs/system/ppc/pseries.rst12
-rw-r--r--docs/system/removed-features.rst4
-rw-r--r--docs/system/target-ppc.rst53
-rw-r--r--hw/display/sm501.c160
-rw-r--r--hw/display/sm501_template.h131
-rw-r--r--hw/net/fsl_etsec/etsec.c1
-rw-r--r--hw/net/fsl_etsec/rings.c1
-rw-r--r--hw/ppc/e500.c1
-rw-r--r--hw/ppc/spapr.c67
-rw-r--r--hw/ppc/spapr_drc.c110
-rw-r--r--hw/ppc/spapr_pci.c8
-rw-r--r--hw/ppc/trace-events2
-rw-r--r--include/hw/ppc/spapr.h1
-rw-r--r--include/hw/ppc/spapr_drc.h7
-rw-r--r--include/qemu/timer.h8
-rw-r--r--pc-bios/README2
-rw-r--r--pc-bios/slof.binbin968368 -> 968888 bytes
m---------roms/SLOF0
-rw-r--r--target/m68k/cpu.c1
-rw-r--r--target/m68k/cpu.h68
-rw-r--r--target/m68k/op_helper.c17
-rw-r--r--target/m68k/translate.c20
-rw-r--r--target/ppc/int_helper.c13
-rw-r--r--target/ppc/translate_init.c.inc36
-rwxr-xr-xtests/tcg/configure.sh6
-rw-r--r--tests/tcg/ppc64/Makefile.target13
-rw-r--r--tests/tcg/ppc64le/Makefile.target12
-rw-r--r--tests/tcg/ppc64le/bcdsub.c130
-rw-r--r--ui/cocoa.m238
-rw-r--r--ui/gtk.c6
-rw-r--r--util/qemu-timer.c13
35 files changed, 949 insertions, 447 deletions
diff --git a/docs/system/ppc/embedded.rst b/docs/system/ppc/embedded.rst
new file mode 100644
index 0000000000..cfffbda24d
--- /dev/null
+++ b/docs/system/ppc/embedded.rst
@@ -0,0 +1,10 @@
+Embedded family boards
+======================
+
+- ``bamboo`` bamboo
+- ``mpc8544ds`` mpc8544ds
+- ``ppce500`` generic paravirt e500 platform
+- ``ref405ep`` ref405ep
+- ``sam460ex`` aCube Sam460ex
+- ``taihu`` taihu
+- ``virtex-ml507`` Xilinx Virtex ML507 reference design
diff --git a/docs/system/ppc/powermac.rst b/docs/system/ppc/powermac.rst
new file mode 100644
index 0000000000..04334ba210
--- /dev/null
+++ b/docs/system/ppc/powermac.rst
@@ -0,0 +1,34 @@
+PowerMac family boards (``g3beige``, ``mac99``)
+==================================================================
+
+Use the executable ``qemu-system-ppc`` to simulate a complete PowerMac
+PowerPC system.
+
+- ``g3beige`` Heathrow based PowerMAC
+- ``mac99`` Mac99 based PowerMAC
+
+Supported devices
+-----------------
+
+QEMU emulates the following PowerMac peripherals:
+
+ * UniNorth or Grackle PCI Bridge
+ * PCI VGA compatible card with VESA Bochs Extensions
+ * 2 PMAC IDE interfaces with hard disk and CD-ROM support
+ * NE2000 PCI adapters
+ * Non Volatile RAM
+ * VIA-CUDA with ADB keyboard and mouse.
+
+
+Missing devices
+---------------
+
+ * To be identified
+
+Firmware
+--------
+
+Since version 0.9.1, QEMU uses OpenBIOS https://www.openbios.org/ for
+the g3beige and mac99 PowerMac and the 40p machines. OpenBIOS is a free
+(GPL v2) portable firmware implementation. The goal is to implement a
+100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware.
diff --git a/docs/system/ppc/powernv.rst b/docs/system/ppc/powernv.rst
new file mode 100644
index 0000000000..43c58bc32e
--- /dev/null
+++ b/docs/system/ppc/powernv.rst
@@ -0,0 +1,193 @@
+PowerNV family boards (``powernv8``, ``powernv9``)
+==================================================================
+
+PowerNV (as Non-Virtualized) is the "baremetal" platform using the
+OPAL firmware. It runs Linux on IBM and OpenPOWER systems and it can
+be used as an hypervisor OS, running KVM guests, or simply as a host
+OS.
+
+The PowerNV QEMU machine tries to emulate a PowerNV system at the
+level of the skiboot firmware, which loads the OS and provides some
+runtime services. Power Systems have a lower firmware (HostBoot) that
+does low level system initialization, like DRAM training. This is
+beyond the scope of what QEMU addresses today.
+
+Supported devices
+-----------------
+
+ * Multi processor support for POWER8, POWER8NVL and POWER9.
+ * XSCOM, serial communication sideband bus to configure chiplets
+ * Simple LPC Controller
+ * Processor Service Interface (PSI) Controller
+ * Interrupt Controller, XICS (POWER8) and XIVE (POWER9)
+ * POWER8 PHB3 PCIe Host bridge and POWER9 PHB4 PCIe Host bridge
+ * Simple OCC is an on-chip microcontroller used for power management
+ tasks
+ * iBT device to handle BMC communication, with the internal BMC
+ simulator provided by QEMU or an external BMC such as an Aspeed
+ QEMU machine.
+ * PNOR containing the different firmware partitions.
+
+Missing devices
+---------------
+
+A lot is missing, among which :
+
+ * POWER10 processor
+ * XIVE2 (POWER10) interrupt controller
+ * I2C controllers (yet to be merged)
+ * NPU/NPU2/NPU3 controllers
+ * EEH support for PCIe Host bridge controllers
+ * NX controller
+ * VAS controller
+ * chipTOD (Time Of Day)
+ * Self Boot Engine (SBE).
+ * FSI bus
+
+Firmware
+--------
+
+The OPAL firmware (OpenPower Abstraction Layer) for OpenPower systems
+includes the runtime services `skiboot` and the bootloader kernel and
+initramfs `skiroot`. Source code can be found on GitHub:
+
+ https://github.com/open-power.
+
+Prebuilt images of `skiboot` and `skiboot` are made available on the `OpenPOWER <https://openpower.xyz/job/openpower/job/openpower-op-build/>`__ site. To boot a POWER9 machine, use the `witherspoon <https://openpower.xyz/job/openpower/job/openpower-op-build/label=slave,target=witherspoon/lastSuccessfulBuild/>`__ images. For POWER8, use
+the `palmetto <https://openpower.xyz/job/openpower/job/openpower-op-build/label=slave,target=palmetto/lastSuccessfulBuild/>`__ images.
+
+QEMU includes a prebuilt image of `skiboot` which is updated when a
+more recent version is required by the models.
+
+Boot options
+------------
+
+Here is a simple setup with one e1000e NIC :
+
+.. code-block:: bash
+
+ $ qemu-system-ppc64 -m 2G -machine powernv9 -smp 2,cores=2,threads=1 \
+ -accel tcg,thread=single \
+ -device e1000e,netdev=net0,mac=C0:FF:EE:00:00:02,bus=pcie.0,addr=0x0 \
+ -netdev user,id=net0,hostfwd=::20022-:22,hostname=pnv \
+ -kernel ./zImage.epapr \
+ -initrd ./rootfs.cpio.xz \
+ -nographic
+
+and a SATA disk :
+
+.. code-block:: bash
+
+ -device ich9-ahci,id=sata0,bus=pcie.1,addr=0x0 \
+ -drive file=./ubuntu-ppc64le.qcow2,if=none,id=drive0,format=qcow2,cache=none \
+ -device ide-hd,bus=sata0.0,unit=0,drive=drive0,id=ide,bootindex=1 \
+
+Complex PCIe configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+Six PHBs are defined per chip (POWER9) but no default PCI layout is
+provided (to be compatible with libvirt). One PCI device can be added
+on any of the available PCIe slots using command line options such as:
+
+.. code-block:: bash
+
+ -device e1000e,netdev=net0,mac=C0:FF:EE:00:00:02,bus=pcie.0,addr=0x0
+ -netdev bridge,id=net0,helper=/usr/libexec/qemu-bridge-helper,br=virbr0,id=hostnet0
+
+ -device megasas,id=scsi0,bus=pcie.0,addr=0x0
+ -drive file=./ubuntu-ppc64le.qcow2,if=none,id=drive-scsi0-0-0-0,format=qcow2,cache=none
+ -device scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0,bootindex=2
+
+Here is a full example with two different storage controllers on
+different PHBs, each with a disk, the second PHB is empty :
+
+.. code-block:: bash
+
+ $ qemu-system-ppc64 -m 2G -machine powernv9 -smp 2,cores=2,threads=1 -accel tcg,thread=single \
+ -kernel ./zImage.epapr -initrd ./rootfs.cpio.xz -bios ./skiboot.lid \
+ \
+ -device megasas,id=scsi0,bus=pcie.0,addr=0x0 \
+ -drive file=./rhel7-ppc64le.qcow2,if=none,id=drive-scsi0-0-0-0,format=qcow2,cache=none \
+ -device scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0,bootindex=2 \
+ \
+ -device pcie-pci-bridge,id=bridge1,bus=pcie.1,addr=0x0 \
+ \
+ -device ich9-ahci,id=sata0,bus=bridge1,addr=0x1 \
+ -drive file=./ubuntu-ppc64le.qcow2,if=none,id=drive0,format=qcow2,cache=none \
+ -device ide-hd,bus=sata0.0,unit=0,drive=drive0,id=ide,bootindex=1 \
+ -device e1000e,netdev=net0,mac=C0:FF:EE:00:00:02,bus=bridge1,addr=0x2 \
+ -netdev bridge,helper=/usr/libexec/qemu-bridge-helper,br=virbr0,id=net0 \
+ -device nec-usb-xhci,bus=bridge1,addr=0x7 \
+ \
+ -serial mon:stdio -nographic
+
+You can also use VIRTIO devices :
+
+.. code-block:: bash
+
+ -drive file=./fedora-ppc64le.qcow2,if=none,snapshot=on,id=drive0 \
+ -device virtio-blk-pci,drive=drive0,id=blk0,bus=pcie.0 \
+ \
+ -netdev tap,helper=/usr/lib/qemu/qemu-bridge-helper,br=virbr0,id=netdev0 \
+ -device virtio-net-pci,netdev=netdev0,id=net0,bus=pcie.1 \
+ \
+ -fsdev local,id=fsdev0,path=$HOME,security_model=passthrough \
+ -device virtio-9p-pci,fsdev=fsdev0,mount_tag=host,bus=pcie.2
+
+Multi sockets
+~~~~~~~~~~~~~
+
+The number of sockets is deduced from the number of CPUs and the
+number of cores. ``-smp 2,cores=1`` will define a machine with 2
+sockets of 1 core, whereas ``-smp 2,cores=2`` will define a machine
+with 1 socket of 2 cores. ``-smp 8,cores=2``, 4 sockets of 2 cores.
+
+BMC configuration
+~~~~~~~~~~~~~~~~~
+
+OpenPOWER systems negotiate the shutdown and reboot with their
+BMC. The QEMU PowerNV machine embeds an IPMI BMC simulator using the
+iBT interface and should offer the same power features.
+
+If you want to define your own BMC, use ``-nodefaults`` and specify
+one on the command line :
+
+.. code-block:: bash
+
+ -device ipmi-bmc-sim,id=bmc0 -device isa-ipmi-bt,bmc=bmc0,irq=10
+
+The files `palmetto-SDR.bin <http://www.kaod.org/qemu/powernv/palmetto-SDR.bin>`__
+and `palmetto-FRU.bin <http://www.kaod.org/qemu/powernv/palmetto-FRU.bin>`__
+define a Sensor Data Record repository and a Field Replaceable Unit
+inventory for a palmetto BMC. They can be used to extend the QEMU BMC
+simulator.
+
+.. code-block:: bash
+
+ -device ipmi-bmc-sim,sdrfile=./palmetto-SDR.bin,fruareasize=256,frudatafile=./palmetto-FRU.bin,id=bmc0 \
+ -device isa-ipmi-bt,bmc=bmc0,irq=10
+
+The PowerNV machine can also be run with an external IPMI BMC device
+connected to a remote QEMU machine acting as BMC, using these options
+:
+
+.. code-block:: bash
+
+ -chardev socket,id=ipmi0,host=localhost,port=9002,reconnect=10 \
+ -device ipmi-bmc-extern,id=bmc0,chardev=ipmi0 \
+ -device isa-ipmi-bt,bmc=bmc0,irq=10 \
+ -nodefaults
+
+NVRAM
+~~~~~
+
+Use a MTD drive to add a PNOR to the machine, and get a NVRAM :
+
+.. code-block:: bash
+
+ -drive file=./witherspoon.pnor,format=raw,if=mtd
+
+CAVEATS
+-------
+
+ * No support for multiple HW threads (SMT=1). Same as pseries.
+ * CPU can hang when doing intensive I/Os. Use ``-append powersave=off`` in that case.
diff --git a/docs/system/ppc/prep.rst b/docs/system/ppc/prep.rst
new file mode 100644
index 0000000000..bd9eb8eabd
--- /dev/null
+++ b/docs/system/ppc/prep.rst
@@ -0,0 +1,18 @@
+Prep machine (``40p``)
+==================================================================
+
+Use the executable ``qemu-system-ppc`` to simulate a complete 40P (PREP)
+
+Supported devices
+-----------------
+
+QEMU emulates the following 40P (PREP) peripherals:
+
+ * PCI Bridge
+ * PCI VGA compatible card with VESA Bochs Extensions
+ * 2 IDE interfaces with hard disk and CD-ROM support
+ * Floppy disk
+ * PCnet network adapters
+ * Serial port
+ * PREP Non Volatile RAM
+ * PC compatible keyboard and mouse.
diff --git a/docs/system/ppc/pseries.rst b/docs/system/ppc/pseries.rst
new file mode 100644
index 0000000000..932d4dd17d
--- /dev/null
+++ b/docs/system/ppc/pseries.rst
@@ -0,0 +1,12 @@
+pSeries family boards (``pseries``)
+===================================
+
+Supported devices
+-----------------
+
+Missing devices
+---------------
+
+
+Firmware
+--------
diff --git a/docs/system/removed-features.rst b/docs/system/removed-features.rst
index 4dcf4f924c..83148dcfda 100644
--- a/docs/system/removed-features.rst
+++ b/docs/system/removed-features.rst
@@ -26,8 +26,8 @@ The ``-no-kvm`` argument was a synonym for setting ``-machine accel=tcg``.
The ``-realtime mlock=on|off`` argument has been replaced by the
``-overcommit mem-lock=on|off`` argument.
-``-show-cursor`` option (since 5.0)
-'''''''''''''''''''''''''''''''''''
+``-show-cursor`` option (removed in 6.0)
+''''''''''''''''''''''''''''''''''''''''
Use ``-display sdl,show-cursor=on``, ``-display gtk,show-cursor=on``
or ``-display default,show-cursor=on`` instead.
diff --git a/docs/system/target-ppc.rst b/docs/system/target-ppc.rst
index a2f04c533c..67905b8f2a 100644
--- a/docs/system/target-ppc.rst
+++ b/docs/system/target-ppc.rst
@@ -3,45 +3,22 @@
PowerPC System emulator
-----------------------
-Use the executable ``qemu-system-ppc`` to simulate a complete 40P (PREP)
-or PowerMac PowerPC system.
+Board-specific documentation
+============================
-QEMU emulates the following PowerMac peripherals:
+You can get a complete list by running ``qemu-system-ppc64 --machine
+help``.
-- UniNorth or Grackle PCI Bridge
+..
+ This table of contents should be kept sorted alphabetically
+ by the title text of each file, which isn't the same ordering
+ as an alphabetical sort by filename.
-- PCI VGA compatible card with VESA Bochs Extensions
+.. toctree::
+ :maxdepth: 1
-- 2 PMAC IDE interfaces with hard disk and CD-ROM support
-
-- NE2000 PCI adapters
-
-- Non Volatile RAM
-
-- VIA-CUDA with ADB keyboard and mouse.
-
-QEMU emulates the following 40P (PREP) peripherals:
-
-- PCI Bridge
-
-- PCI VGA compatible card with VESA Bochs Extensions
-
-- 2 IDE interfaces with hard disk and CD-ROM support
-
-- Floppy disk
-
-- PCnet network adapters
-
-- Serial port
-
-- PREP Non Volatile RAM
-
-- PC compatible keyboard and mouse.
-
-Since version 0.9.1, QEMU uses OpenBIOS https://www.openbios.org/ for
-the g3beige and mac99 PowerMac and the 40p machines. OpenBIOS is a free
-(GPL v2) portable firmware implementation. The goal is to implement a
-100% IEEE 1275-1994 (referred to as Open Firmware) compliant firmware.
-
-More information is available at
-http://perso.magic.fr/l_indien/qemu-ppc/.
+ ppc/embedded
+ ppc/powermac
+ ppc/powernv
+ ppc/prep
+ ppc/pseries
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index 8966b69bc7..8789722ef2 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -1558,86 +1558,85 @@ typedef void draw_hwc_line_func(uint8_t *d, const uint8_t *s,
int width, const uint8_t *palette,
int c_x, int c_y);
-#define DEPTH 8
-#include "sm501_template.h"
-
-#define DEPTH 15
-#include "sm501_template.h"
-
-#define BGR_FORMAT
-#define DEPTH 15
-#include "sm501_template.h"
-
-#define DEPTH 16
-#include "sm501_template.h"
-
-#define BGR_FORMAT
-#define DEPTH 16
-#include "sm501_template.h"
-
-#define DEPTH 32
-#include "sm501_template.h"
-
-#define BGR_FORMAT
-#define DEPTH 32
-#include "sm501_template.h"
-
-static draw_line_func *draw_line8_funcs[] = {
- draw_line8_8,
- draw_line8_15,
- draw_line8_16,
- draw_line8_32,
- draw_line8_32bgr,
- draw_line8_15bgr,
- draw_line8_16bgr,
-};
-
-static draw_line_func *draw_line16_funcs[] = {
- draw_line16_8,
- draw_line16_15,
- draw_line16_16,
- draw_line16_32,
- draw_line16_32bgr,
- draw_line16_15bgr,
- draw_line16_16bgr,
-};
+static void draw_line8_32(uint8_t *d, const uint8_t *s, int width,
+ const uint32_t *pal)
+{
+ uint8_t v, r, g, b;
+ do {
+ v = ldub_p(s);
+ r = (pal[v] >> 16) & 0xff;
+ g = (pal[v] >> 8) & 0xff;
+ b = (pal[v] >> 0) & 0xff;
+ *(uint32_t *)d = rgb_to_pixel32(r, g, b);
+ s++;
+ d += 4;
+ } while (--width != 0);
+}
-static draw_line_func *draw_line32_funcs[] = {
- draw_line32_8,
- draw_line32_15,
- draw_line32_16,
- draw_line32_32,
- draw_line32_32bgr,
- draw_line32_15bgr,
- draw_line32_16bgr,
-};
+static void draw_line16_32(uint8_t *d, const uint8_t *s, int width,
+ const uint32_t *pal)
+{
+ uint16_t rgb565;
+ uint8_t r, g, b;
+
+ do {
+ rgb565 = lduw_le_p(s);
+ r = (rgb565 >> 8) & 0xf8;
+ g = (rgb565 >> 3) & 0xfc;
+ b = (rgb565 << 3) & 0xf8;
+ *(uint32_t *)d = rgb_to_pixel32(r, g, b);
+ s += 2;
+ d += 4;
+ } while (--width != 0);
+}
-static draw_hwc_line_func *draw_hwc_line_funcs[] = {
- draw_hwc_line_8,
- draw_hwc_line_15,
- draw_hwc_line_16,
- draw_hwc_line_32,
- draw_hwc_line_32bgr,
- draw_hwc_line_15bgr,
- draw_hwc_line_16bgr,
-};
+static void draw_line32_32(uint8_t *d, const uint8_t *s, int width,
+ const uint32_t *pal)
+{
+ uint8_t r, g, b;
+
+ do {
+ r = s[2];
+ g = s[1];
+ b = s[0];
+ *(uint32_t *)d = rgb_to_pixel32(r, g, b);
+ s += 4;
+ d += 4;
+ } while (--width != 0);
+}
-static inline int get_depth_index(DisplaySurface *surface)
+/**
+ * Draw hardware cursor image on the given line.
+ */
+static void draw_hwc_line_32(uint8_t *d, const uint8_t *s, int width,
+ const uint8_t *palette, int c_x, int c_y)
{
- switch (surface_bits_per_pixel(surface)) {
- default:
- case 8:
- return 0;
- case 15:
- return 1;
- case 16:
- return 2;
- case 32:
- if (is_surface_bgr(surface)) {
- return 4;
- } else {
- return 3;
+ int i;
+ uint8_t r, g, b, v, bitset = 0;
+
+ /* get cursor position */
+ assert(0 <= c_y && c_y < SM501_HWC_HEIGHT);
+ s += SM501_HWC_WIDTH * c_y / 4; /* 4 pixels per byte */
+ d += c_x * 4;
+
+ for (i = 0; i < SM501_HWC_WIDTH && c_x + i < width; i++) {
+ /* get pixel value */
+ if (i % 4 == 0) {
+ bitset = ldub_p(s);
+ s++;
}
+ v = bitset & 3;
+ bitset >>= 2;
+
+ /* write pixel */
+ if (v) {
+ v--;
+ r = palette[v * 3 + 0];
+ g = palette[v * 3 + 1];
+ b = palette[v * 3 + 2];
+ *(uint32_t *)d = rgb_to_pixel32(r, g, b);
+ }
+ d += 4;
}
}
@@ -1652,7 +1651,6 @@ static void sm501_update_display(void *opaque)
int height = get_height(s, crt);
int src_bpp = get_bpp(s, crt);
int dst_bpp = surface_bytes_per_pixel(surface);
- int dst_depth_index = get_depth_index(surface);
draw_line_func *draw_line = NULL;
draw_hwc_line_func *draw_hwc_line = NULL;
int full_update = 0;
@@ -1662,6 +1660,8 @@ static void sm501_update_display(void *opaque)
uint8_t hwc_palette[3 * 3];
uint8_t *hwc_src = NULL;
+ assert(dst_bpp == 4); /* Output is always 32-bit RGB */
+
if (!((crt ? s->dc_crt_control : s->dc_panel_control)
& SM501_DC_CRT_CONTROL_ENABLE)) {
return;
@@ -1674,13 +1674,13 @@ static void sm501_update_display(void *opaque)
/* choose draw_line function */
switch (src_bpp) {
case 1:
- draw_line = draw_line8_funcs[dst_depth_index];
+ draw_line = draw_line8_32;
break;
case 2:
- draw_line = draw_line16_funcs[dst_depth_index];
+ draw_line = draw_line16_32;
break;
case 4:
- draw_line = draw_line32_funcs[dst_depth_index];
+ draw_line = draw_line32_32;
break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "sm501: update display"
@@ -1691,7 +1691,7 @@ static void sm501_update_display(void *opaque)
/* set up to draw hardware cursor */
if (is_hwc_enabled(s, crt)) {
/* choose cursor draw line function */
- draw_hwc_line = draw_hwc_line_funcs[dst_depth_index];
+ draw_hwc_line = draw_hwc_line_32;
hwc_src = get_hwc_address(s, crt);
c_x = get_hwc_x(s, crt);
c_y = get_hwc_y(s, crt);
diff --git a/hw/display/sm501_template.h b/hw/display/sm501_template.h
deleted file mode 100644
index a60abad019..0000000000
--- a/hw/display/sm501_template.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Pixel drawing function templates for QEMU SM501 Device
- *
- * Copyright (c) 2008 Shin-ichiro KAWASAKI
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#if DEPTH == 8
-#define BPP 1
-#define PIXEL_TYPE uint8_t
-#elif DEPTH == 15 || DEPTH == 16
-#define BPP 2
-#define PIXEL_TYPE uint16_t
-#elif DEPTH == 32
-#define BPP 4
-#define PIXEL_TYPE uint32_t
-#else
-#error unsupport depth
-#endif
-
-#ifdef BGR_FORMAT
-#define PIXEL_NAME glue(DEPTH, bgr)
-#else
-#define PIXEL_NAME DEPTH
-#endif /* BGR_FORMAT */
-
-
-static void glue(draw_line8_, PIXEL_NAME)(
- uint8_t *d, const uint8_t *s, int width, const uint32_t *pal)
-{
- uint8_t v, r, g, b;
- do {
- v = ldub_p(s);
- r = (pal[v] >> 16) & 0xff;
- g = (pal[v] >> 8) & 0xff;
- b = (pal[v] >> 0) & 0xff;
- *(PIXEL_TYPE *)d = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
- s++;
- d += BPP;
- } while (--width != 0);
-}
-
-static void glue(draw_line16_, PIXEL_NAME)(
- uint8_t *d, const uint8_t *s, int width, const uint32_t *pal)
-{
- uint16_t rgb565;
- uint8_t r, g, b;
-
- do {
- rgb565 = lduw_le_p(s);
- r = (rgb565 >> 8) & 0xf8;
- g = (rgb565 >> 3) & 0xfc;
- b = (rgb565 << 3) & 0xf8;
- *(PIXEL_TYPE *)d = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
- s += 2;
- d += BPP;
- } while (--width != 0);
-}
-
-static void glue(draw_line32_, PIXEL_NAME)(
- uint8_t *d, const uint8_t *s, int width, const uint32_t *pal)
-{
- uint8_t r, g, b;
-
- do {
- r = s[2];
- g = s[1];
- b = s[0];
- *(PIXEL_TYPE *)d = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
- s += 4;
- d += BPP;
- } while (--width != 0);
-}
-
-/**
- * Draw hardware cursor image on the given line.
- */
-static void glue(draw_hwc_line_, PIXEL_NAME)(uint8_t *d, const uint8_t *s,
- int width, const uint8_t *palette, int c_x, int c_y)
-{
- int i;
- uint8_t r, g, b, v, bitset = 0;
-
- /* get cursor position */
- assert(0 <= c_y && c_y < SM501_HWC_HEIGHT);
- s += SM501_HWC_WIDTH * c_y / 4; /* 4 pixels per byte */
- d += c_x * BPP;
-
- for (i = 0; i < SM501_HWC_WIDTH && c_x + i < width; i++) {
- /* get pixel value */
- if (i % 4 == 0) {
- bitset = ldub_p(s);
- s++;
- }
- v = bitset & 3;
- bitset >>= 2;
-
- /* write pixel */
- if (v) {
- v--;
- r = palette[v * 3 + 0];
- g = palette[v * 3 + 1];
- b = palette[v * 3 + 2];
- *(PIXEL_TYPE *)d = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
- }
- d += BPP;
- }
-}
-
-#undef DEPTH
-#undef BPP
-#undef PIXEL_TYPE
-#undef PIXEL_NAME
-#undef BGR_FORMAT
diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c
index 93886bba60..bd9d62b559 100644
--- a/hw/net/fsl_etsec/etsec.c
+++ b/hw/net/fsl_etsec/etsec.c
@@ -27,6 +27,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu-common.h"
#include "hw/sysbus.h"
#include "hw/irq.h"
#include "hw/ptimer.h"
diff --git a/hw/net/fsl_etsec/rings.c b/hw/net/fsl_etsec/rings.c
index fe055d3381..d6be0d7d18 100644
--- a/hw/net/fsl_etsec/rings.c
+++ b/hw/net/fsl_etsec/rings.c
@@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
#include "qemu/osdep.h"
+#include "qemu-common.h"
#include "net/checksum.h"
#include "qemu/log.h"
#include "etsec.h"
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 01517a6c6c..1d94485ac8 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -231,6 +231,7 @@ static int create_devtree_etsec(SysBusDevice *sbdev, PlatformDevtreeData *data)
assert(irq2 >= 0);
qemu_fdt_add_subnode(fdt, node);
+ qemu_fdt_setprop(fdt, node, "ranges", NULL, 0);
qemu_fdt_setprop_string(fdt, node, "device_type", "network");
qemu_fdt_setprop_string(fdt, node, "compatible", "fsl,etsec2");
qemu_fdt_setprop_string(fdt, node, "model", "eTSEC");
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 85fe65f894..d56418ca29 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -28,6 +28,7 @@
#include "qemu-common.h"
#include "qemu/datadir.h"
#include "qapi/error.h"
+#include "qapi/qapi-events-machine.h"
#include "qapi/visitor.h"
#include "sysemu/sysemu.h"
#include "sysemu/hostmem.h"
@@ -3575,6 +3576,57 @@ static SpaprDimmState *spapr_recover_pending_dimm_state(SpaprMachineState *ms,
return spapr_pending_dimm_unplugs_add(ms, avail_lmbs, dimm);
}
+void spapr_memory_unplug_rollback(SpaprMachineState *spapr, DeviceState *dev)
+{
+ SpaprDimmState *ds;
+ PCDIMMDevice *dimm;
+ SpaprDrc *drc;
+ uint32_t nr_lmbs;
+ uint64_t size, addr_start, addr;
+ g_autofree char *qapi_error = NULL;
+ int i;
+
+ if (!dev) {
+ return;
+ }
+
+ dimm = PC_DIMM(dev);
+ ds = spapr_pending_dimm_unplugs_find(spapr, dimm);
+
+ /*
+ * 'ds == NULL' would mean that the DIMM doesn't have a pending
+ * unplug state, but one of its DRC is marked as unplug_requested.
+ * This is bad and weird enough to g_assert() out.
+ */
+ g_assert(ds);
+
+ spapr_pending_dimm_unplugs_remove(spapr, ds);
+
+ size = memory_device_get_region_size(MEMORY_DEVICE(dimm), &error_abort);
+ nr_lmbs = size / SPAPR_MEMORY_BLOCK_SIZE;
+
+ addr_start = object_property_get_uint(OBJECT(dimm), PC_DIMM_ADDR_PROP,
+ &error_abort);
+
+ addr = addr_start;
+ for (i = 0; i < nr_lmbs; i++) {
+ drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
+ addr / SPAPR_MEMORY_BLOCK_SIZE);
+ g_assert(drc);
+
+ drc->unplug_requested = false;
+ addr += SPAPR_MEMORY_BLOCK_SIZE;
+ }
+
+ /*
+ * Tell QAPI that something happened and the memory
+ * hotunplug wasn't successful.
+ */
+ qapi_error = g_strdup_printf("Memory hotunplug rejected by the guest "
+ "for device %s", dev->id);
+ qapi_event_send_mem_unplug_error(dev->id, qapi_error);
+}
+
/* Callback to be called during DRC release. */
void spapr_lmb_release(DeviceState *dev)
{
@@ -3654,13 +3706,12 @@ static void spapr_memory_unplug_request(HotplugHandler *hotplug_dev,
addr / SPAPR_MEMORY_BLOCK_SIZE);
g_assert(drc);
- spapr_drc_detach(drc);
+ spapr_drc_unplug_request(drc);
addr += SPAPR_MEMORY_BLOCK_SIZE;
}
drc = spapr_drc_by_id(TYPE_SPAPR_DRC_LMB,
addr_start / SPAPR_MEMORY_BLOCK_SIZE);
- g_assert(drc);
spapr_hotplug_req_remove_by_count_indexed(SPAPR_DR_CONNECTOR_TYPE_LMB,
nr_lmbs, spapr_drc_index(drc));
}
@@ -3722,8 +3773,12 @@ void spapr_core_unplug_request(HotplugHandler *hotplug_dev, DeviceState *dev,
g_assert(drc);
if (!spapr_drc_unplug_requested(drc)) {
- spapr_drc_detach(drc);
+ spapr_drc_unplug_request(drc);
spapr_hotplug_req_remove_by_index(drc);
+ } else {
+ error_setg(errp, "core-id %d unplug is still pending, %d seconds "
+ "timeout remaining",
+ cc->core_id, spapr_drc_unplug_timeout_remaining_sec(drc));
}
}
@@ -3985,8 +4040,12 @@ static void spapr_phb_unplug_request(HotplugHandler *hotplug_dev,
assert(drc);
if (!spapr_drc_unplug_requested(drc)) {
- spapr_drc_detach(drc);
+ spapr_drc_unplug_request(drc);
spapr_hotplug_req_remove_by_index(drc);
+ } else {
+ error_setg(errp,
+ "PCI Host Bridge unplug already in progress for device %s",
+ dev->id);
}
}
diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
index 8571d5bafe..8a71b03800 100644
--- a/hw/ppc/spapr_drc.c
+++ b/hw/ppc/spapr_drc.c
@@ -50,6 +50,22 @@ uint32_t spapr_drc_index(SpaprDrc *drc)
| (drc->id & DRC_INDEX_ID_MASK);
}
+static void spapr_drc_release(SpaprDrc *drc)
+{
+ SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+
+ drck->release(drc->dev);
+
+ drc->unplug_requested = false;
+ timer_del(drc->unplug_timeout_timer);
+
+ g_free(drc->fdt);
+ drc->fdt = NULL;
+ drc->fdt_start_offset = 0;
+ object_property_del(OBJECT(drc), "device");
+ drc->dev = NULL;
+}
+
static uint32_t drc_isolate_physical(SpaprDrc *drc)
{
switch (drc->state) {
@@ -68,7 +84,7 @@ static uint32_t drc_isolate_physical(SpaprDrc *drc)
if (drc->unplug_requested) {
uint32_t drc_index = spapr_drc_index(drc);
trace_spapr_drc_set_isolation_state_finalizing(drc_index);
- spapr_drc_detach(drc);
+ spapr_drc_release(drc);
}
return RTAS_OUT_SUCCESS;
@@ -132,19 +148,6 @@ static uint32_t drc_isolate_logical(SpaprDrc *drc)
drc->state = SPAPR_DRC_STATE_LOGICAL_AVAILABLE;
- /* if we're awaiting release, but still in an unconfigured state,
- * it's likely the guest is still in the process of configuring
- * the device and is transitioning the devices to an ISOLATED
- * state as a part of that process. so we only complete the
- * removal when this transition happens for a device in a
- * configured state, as suggested by the state diagram from PAPR+
- * 2.7, 13.4
- */
- if (drc->unplug_requested) {
- uint32_t drc_index = spapr_drc_index(drc);
- trace_spapr_drc_set_isolation_state_finalizing(drc_index);
- spapr_drc_detach(drc);
- }
return RTAS_OUT_SUCCESS;
}
@@ -222,7 +225,7 @@ static uint32_t drc_set_unusable(SpaprDrc *drc)
if (drc->unplug_requested) {
uint32_t drc_index = spapr_drc_index(drc);
trace_spapr_drc_set_allocation_state_finalizing(drc_index);
- spapr_drc_detach(drc);
+ spapr_drc_release(drc);
}
return RTAS_OUT_SUCCESS;
@@ -369,6 +372,17 @@ static void prop_get_fdt(Object *obj, Visitor *v, const char *name,
} while (fdt_depth != 0);
}
+static void spapr_drc_start_unplug_timeout_timer(SpaprDrc *drc)
+{
+ SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+
+ if (drck->unplug_timeout_seconds != 0) {
+ timer_mod(drc->unplug_timeout_timer,
+ qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
+ drck->unplug_timeout_seconds * 1000);
+ }
+}
+
void spapr_drc_attach(SpaprDrc *drc, DeviceState *d)
{
trace_spapr_drc_attach(spapr_drc_index(drc));
@@ -385,30 +399,18 @@ void spapr_drc_attach(SpaprDrc *drc, DeviceState *d)
NULL, 0);
}
-static void spapr_drc_release(SpaprDrc *drc)
-{
- SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
-
- drck->release(drc->dev);
-
- drc->unplug_requested = false;
- g_free(drc->fdt);
- drc->fdt = NULL;
- drc->fdt_start_offset = 0;
- object_property_del(OBJECT(drc), "device");
- drc->dev = NULL;
-}
-
-void spapr_drc_detach(SpaprDrc *drc)
+void spapr_drc_unplug_request(SpaprDrc *drc)
{
SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
- trace_spapr_drc_detach(spapr_drc_index(drc));
+ trace_spapr_drc_unplug_request(spapr_drc_index(drc));
g_assert(drc->dev);
drc->unplug_requested = true;
+ spapr_drc_start_unplug_timeout_timer(drc);
+
if (drc->state != drck->empty_state) {
trace_spapr_drc_awaiting_quiesce(spapr_drc_index(drc));
return;
@@ -417,6 +419,15 @@ void spapr_drc_detach(SpaprDrc *drc)
spapr_drc_release(drc);
}
+int spapr_drc_unplug_timeout_remaining_sec(SpaprDrc *drc)
+{
+ if (drc->unplug_requested) {
+ return timer_deadline_ms(drc->unplug_timeout_timer) / 1000;
+ }
+
+ return 0;
+}
+
bool spapr_drc_reset(SpaprDrc *drc)
{
SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
@@ -488,11 +499,23 @@ static bool spapr_drc_needed(void *opaque)
spapr_drc_unplug_requested(drc);
}
+static int spapr_drc_post_load(void *opaque, int version_id)
+{
+ SpaprDrc *drc = opaque;
+
+ if (drc->unplug_requested) {
+ spapr_drc_start_unplug_timeout_timer(drc);
+ }
+
+ return 0;
+}
+
static const VMStateDescription vmstate_spapr_drc = {
.name = "spapr_drc",
.version_id = 1,
.minimum_version_id = 1,
.needed = spapr_drc_needed,
+ .post_load = spapr_drc_post_load,
.fields = (VMStateField []) {
VMSTATE_UINT32(state, SpaprDrc),
VMSTATE_END_OF_LIST()
@@ -503,6 +526,15 @@ static const VMStateDescription vmstate_spapr_drc = {
}
};
+static void drc_unplug_timeout_cb(void *opaque)
+{
+ SpaprDrc *drc = opaque;
+
+ if (drc->unplug_requested) {
+ drc->unplug_requested = false;
+ }
+}
+
static void drc_realize(DeviceState *d, Error **errp)
{
SpaprDrc *drc = SPAPR_DR_CONNECTOR(d);
@@ -525,6 +557,11 @@ static void drc_realize(DeviceState *d, Error **errp)
object_property_add_alias(root_container, link_name,
drc->owner, child_name);
g_free(link_name);
+
+ drc->unplug_timeout_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
+ drc_unplug_timeout_cb,
+ drc);
+
vmstate_register(VMSTATE_IF(drc), spapr_drc_index(drc), &vmstate_spapr_drc,
drc);
trace_spapr_drc_realize_complete(spapr_drc_index(drc));
@@ -542,6 +579,7 @@ static void drc_unrealize(DeviceState *d)
name = g_strdup_printf("%x", spapr_drc_index(drc));
object_property_del(root_container, name);
g_free(name);
+ timer_free(drc->unplug_timeout_timer);
}
SpaprDrc *spapr_dr_connector_new(Object *owner, const char *type,
@@ -683,6 +721,7 @@ static void spapr_drc_cpu_class_init(ObjectClass *k, void *data)
drck->drc_name_prefix = "CPU ";
drck->release = spapr_core_release;
drck->dt_populate = spapr_core_dt_populate;
+ drck->unplug_timeout_seconds = 15;
}
static void spapr_drc_pci_class_init(ObjectClass *k, void *data)
@@ -1190,6 +1229,15 @@ static void rtas_ibm_configure_connector(PowerPCCPU *cpu,
drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ /*
+ * This indicates that the kernel is reconfiguring a LMB due to
+ * a failed hotunplug. Rollback the DIMM unplug process.
+ */
+ if (spapr_drc_type(drc) == SPAPR_DR_CONNECTOR_TYPE_LMB &&
+ drc->unplug_requested) {
+ spapr_memory_unplug_rollback(spapr, drc->dev);
+ }
+
if (!drc->fdt) {
void *fdt;
int fdt_size;
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index f1c7479816..feba18cb12 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -1723,12 +1723,12 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler,
* functions, even if their unplug weren't requested
* beforehand.
*/
- spapr_drc_detach(func_drc);
+ spapr_drc_unplug_request(func_drc);
}
}
}
- spapr_drc_detach(drc);
+ spapr_drc_unplug_request(drc);
/* if this isn't func 0, defer unplug event. otherwise signal removal
* for all present functions
@@ -1743,6 +1743,10 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler,
}
}
}
+ } else {
+ error_setg(errp,
+ "PCI device unplug already in progress for device %s",
+ drc->dev->id);
}
}
diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events
index 1e91984526..b4bbfbb013 100644
--- a/hw/ppc/trace-events
+++ b/hw/ppc/trace-events
@@ -50,7 +50,7 @@ spapr_drc_set_allocation_state(uint32_t index, int state) "drc: 0x%"PRIx32", sta
spapr_drc_set_allocation_state_finalizing(uint32_t index) "drc: 0x%"PRIx32
spapr_drc_set_configured(uint32_t index) "drc: 0x%"PRIx32
spapr_drc_attach(uint32_t index) "drc: 0x%"PRIx32
-spapr_drc_detach(uint32_t index) "drc: 0x%"PRIx32
+spapr_drc_unplug_request(uint32_t index) "drc: 0x%"PRIx32
spapr_drc_awaiting_quiesce(uint32_t index) "drc: 0x%"PRIx32
spapr_drc_reset(uint32_t index) "drc: 0x%"PRIx32
spapr_drc_realize(uint32_t index) "drc: 0x%"PRIx32
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index ccbeeca1de..47cebaf3ac 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -847,6 +847,7 @@ int spapr_hpt_shift_for_ramsize(uint64_t ramsize);
int spapr_reallocate_hpt(SpaprMachineState *spapr, int shift, Error **errp);
void spapr_clear_pending_events(SpaprMachineState *spapr);
void spapr_clear_pending_hotplug_events(SpaprMachineState *spapr);
+void spapr_memory_unplug_rollback(SpaprMachineState *spapr, DeviceState *dev);
int spapr_max_server_number(SpaprMachineState *spapr);
void spapr_store_hpte(PowerPCCPU *cpu, hwaddr ptex,
uint64_t pte0, uint64_t pte1);
diff --git a/include/hw/ppc/spapr_drc.h b/include/hw/ppc/spapr_drc.h
index 8982927d5c..26599c385a 100644
--- a/include/hw/ppc/spapr_drc.h
+++ b/include/hw/ppc/spapr_drc.h
@@ -187,6 +187,8 @@ typedef struct SpaprDrc {
bool unplug_requested;
void *fdt;
int fdt_start_offset;
+
+ QEMUTimer *unplug_timeout_timer;
} SpaprDrc;
struct SpaprMachineState;
@@ -209,6 +211,8 @@ typedef struct SpaprDrcClass {
int (*dt_populate)(SpaprDrc *drc, struct SpaprMachineState *spapr,
void *fdt, int *fdt_start_offset, Error **errp);
+
+ int unplug_timeout_seconds;
} SpaprDrcClass;
typedef struct SpaprDrcPhysical {
@@ -243,7 +247,8 @@ int spapr_dt_drc(void *fdt, int offset, Object *owner, uint32_t drc_type_mask);
* beforehand (eg. check drc->dev at pre-plug).
*/
void spapr_drc_attach(SpaprDrc *drc, DeviceState *d);
-void spapr_drc_detach(SpaprDrc *drc);
+void spapr_drc_unplug_request(SpaprDrc *drc);
+int spapr_drc_unplug_timeout_remaining_sec(SpaprDrc *drc);
/*
* Reset all DRCs, causing pending hot-plug/unplug requests to complete.
diff --git a/include/qemu/timer.h b/include/qemu/timer.h
index 1678238384..5e76e3f8c2 100644
--- a/include/qemu/timer.h
+++ b/include/qemu/timer.h
@@ -795,6 +795,14 @@ static inline int64_t get_max_clock_jump(void)
return 60 * NANOSECONDS_PER_SECOND;
}
+/**
+ * timer_deadline_ms:
+ *
+ * Returns the remaining miliseconds for @timer to expire, or zero
+ * if the timer is no longer pending.
+ */
+int64_t timer_deadline_ms(QEMUTimer *timer);
+
/*
* Low level clock functions
*/
diff --git a/pc-bios/README b/pc-bios/README
index db7129ef64..c101c9a04f 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -14,7 +14,7 @@
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
implementation for certain IBM POWER hardware. The sources are at
https://github.com/aik/SLOF, and the image currently in qemu is
- built from git tag qemu-slof-20200717.
+ built from git tag qemu-slof-20210217.
- sgabios (the Serial Graphics Adapter option ROM) provides a means for
legacy x86 software to communicate with an attached serial console as
diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin
index 448dcada36..3f3918a9e1 100644
--- a/pc-bios/slof.bin
+++ b/pc-bios/slof.bin
Binary files differ
diff --git a/roms/SLOF b/roms/SLOF
-Subproject e18ddad8516ff2cfe36ec130200318f7251aa78
+Subproject 33a7322de13e9dca4b38851a345a58d37e7a441
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
index 37d2ed9dc7..a14874b4da 100644
--- a/target/m68k/cpu.c
+++ b/target/m68k/cpu.c
@@ -161,6 +161,7 @@ static void m68020_cpu_initfn(Object *obj)
m68k_set_feature(env, M68K_FEATURE_CAS);
m68k_set_feature(env, M68K_FEATURE_CHK2);
m68k_set_feature(env, M68K_FEATURE_MSP);
+ m68k_set_feature(env, M68K_FEATURE_UNALIGNED_DATA);
}
/*
diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h
index 7c3feeaf8a..402c86c876 100644
--- a/target/m68k/cpu.h
+++ b/target/m68k/cpu.h
@@ -475,36 +475,60 @@ void do_m68k_semihosting(CPUM68KState *env, int nr);
*/
enum m68k_features {
- M68K_FEATURE_M68000, /* Base m68k instruction set */
+ /* Base m68k instruction set */
+ M68K_FEATURE_M68000,
M68K_FEATURE_M68010,
M68K_FEATURE_M68020,
M68K_FEATURE_M68030,
M68K_FEATURE_M68040,
M68K_FEATURE_M68060,
- M68K_FEATURE_CF_ISA_A, /* Base Coldfire set Rev A. */
- M68K_FEATURE_CF_ISA_B, /* (ISA B or C). */
- M68K_FEATURE_CF_ISA_APLUSC, /* BIT/BITREV, FF1, STRLDSR (ISA A+ or C). */
- M68K_FEATURE_BRAL, /* BRA with Long branch. (680[2346]0, ISA A+ or B). */
+ /* Base Coldfire set Rev A. */
+ M68K_FEATURE_CF_ISA_A,
+ /* (ISA B or C). */
+ M68K_FEATURE_CF_ISA_B,
+ /* BIT/BITREV, FF1, STRLDSR (ISA A+ or C). */
+ M68K_FEATURE_CF_ISA_APLUSC,
+ /* BRA with Long branch. (680[2346]0, ISA A+ or B). */
+ M68K_FEATURE_BRAL,
M68K_FEATURE_CF_FPU,
M68K_FEATURE_CF_MAC,
M68K_FEATURE_CF_EMAC,
- M68K_FEATURE_CF_EMAC_B, /* Revision B EMAC (dual accumulate). */
- M68K_FEATURE_USP, /* User Stack Pointer. (680[012346]0, ISA A+, B or C).*/
- M68K_FEATURE_MSP, /* Master Stack Pointer. (680[234]0) */
- M68K_FEATURE_EXT_FULL, /* 68020+ full extension word. */
- M68K_FEATURE_WORD_INDEX, /* word sized address index registers. */
- M68K_FEATURE_SCALED_INDEX, /* scaled address index registers. */
- M68K_FEATURE_LONG_MULDIV, /* 32 bit mul/div. (680[2346]0, and CPU32) */
- M68K_FEATURE_QUAD_MULDIV, /* 64 bit mul/div. (680[2346]0, and CPU32) */
- M68K_FEATURE_BCCL, /* Bcc with Long branches. (680[2346]0, and CPU32) */
- M68K_FEATURE_BITFIELD, /* BFxxx Bit field insns. (680[2346]0) */
- M68K_FEATURE_FPU, /* fpu insn. (680[46]0) */
- M68K_FEATURE_CAS, /* CAS/CAS2[WL] insns. (680[2346]0) */
- M68K_FEATURE_BKPT, /* BKPT insn. (680[12346]0, and CPU32) */
- M68K_FEATURE_RTD, /* RTD insn. (680[12346]0, and CPU32) */
- M68K_FEATURE_CHK2, /* CHK2 insn. (680[2346]0, and CPU32) */
- M68K_FEATURE_MOVEP, /* MOVEP insn. (680[01234]0, and CPU32) */
- M68K_FEATURE_MOVEC, /* MOVEC insn. (from 68010) */
+ /* Revision B EMAC (dual accumulate). */
+ M68K_FEATURE_CF_EMAC_B,
+ /* User Stack Pointer. (680[012346]0, ISA A+, B or C). */
+ M68K_FEATURE_USP,
+ /* Master Stack Pointer. (680[234]0) */
+ M68K_FEATURE_MSP,
+ /* 68020+ full extension word. */
+ M68K_FEATURE_EXT_FULL,
+ /* word sized address index registers. */
+ M68K_FEATURE_WORD_INDEX,
+ /* scaled address index registers. */
+ M68K_FEATURE_SCALED_INDEX,
+ /* 32 bit mul/div. (680[2346]0, and CPU32) */
+ M68K_FEATURE_LONG_MULDIV,
+ /* 64 bit mul/div. (680[2346]0, and CPU32) */
+ M68K_FEATURE_QUAD_MULDIV,
+ /* Bcc with Long branches. (680[2346]0, and CPU32) */
+ M68K_FEATURE_BCCL,
+ /* BFxxx Bit field insns. (680[2346]0) */
+ M68K_FEATURE_BITFIELD,
+ /* fpu insn. (680[46]0) */
+ M68K_FEATURE_FPU,
+ /* CAS/CAS2[WL] insns. (680[2346]0) */
+ M68K_FEATURE_CAS,
+ /* BKPT insn. (680[12346]0, and CPU32) */
+ M68K_FEATURE_BKPT,
+ /* RTD insn. (680[12346]0, and CPU32) */
+ M68K_FEATURE_RTD,
+ /* CHK2 insn. (680[2346]0, and CPU32) */
+ M68K_FEATURE_CHK2,
+ /* MOVEP insn. (680[01234]0, and CPU32) */
+ M68K_FEATURE_MOVEP,
+ /* MOVEC insn. (from 68010) */
+ M68K_FEATURE_MOVEC,
+ /* Unaligned data accesses (680[2346]0) */
+ M68K_FEATURE_UNALIGNED_DATA,
};
static inline int m68k_feature(CPUM68KState *env, int feature)
diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c
index 9b0698f267..ae1ba4b437 100644
--- a/target/m68k/op_helper.c
+++ b/target/m68k/op_helper.c
@@ -348,7 +348,10 @@ static void m68k_interrupt_all(CPUM68KState *env, int is_hw)
cpu_m68k_set_sr(env, sr);
sp = env->aregs[7];
- sp &= ~1;
+ if (!m68k_feature(env, M68K_FEATURE_UNALIGNED_DATA)) {
+ sp &= ~1;
+ }
+
if (cs->exception_index == EXCP_ACCESS) {
if (env->mmu.fault) {
cpu_abort(cs, "DOUBLE MMU FAULT\n");
@@ -468,7 +471,17 @@ void m68k_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr,
if (m68k_feature(env, M68K_FEATURE_M68040)) {
env->mmu.mmusr = 0;
- env->mmu.ssw |= M68K_ATC_040;
+
+ /*
+ * According to the MC68040 users manual the ATC bit of the SSW is
+ * used to distinguish between ATC faults and physical bus errors.
+ * In the case of a bus error e.g. during nubus read from an empty
+ * slot this bit should not be set
+ */
+ if (response != MEMTX_DECODE_ERROR) {
+ env->mmu.ssw |= M68K_ATC_040;
+ }
+
/* FIXME: manage MMU table access error */
env->mmu.ssw &= ~M68K_TM_040;
if (env->sr & SR_S) { /* SUPERVISOR */
diff --git a/target/m68k/translate.c b/target/m68k/translate.c
index ac936ebe8f..200018ae6a 100644
--- a/target/m68k/translate.c
+++ b/target/m68k/translate.c
@@ -2969,6 +2969,25 @@ DISAS_INSN(rtd)
gen_jmp(s, tmp);
}
+DISAS_INSN(rtr)
+{
+ TCGv tmp;
+ TCGv ccr;
+ TCGv sp;
+
+ sp = tcg_temp_new();
+ ccr = gen_load(s, OS_WORD, QREG_SP, 0, IS_USER(s));
+ tcg_gen_addi_i32(sp, QREG_SP, 2);
+ tmp = gen_load(s, OS_LONG, sp, 0, IS_USER(s));
+ tcg_gen_addi_i32(QREG_SP, sp, 4);
+ tcg_temp_free(sp);
+
+ gen_set_sr(s, ccr, true);
+ tcg_temp_free(ccr);
+
+ gen_jmp(s, tmp);
+}
+
DISAS_INSN(rts)
{
TCGv tmp;
@@ -6015,6 +6034,7 @@ void register_m68k_insns (CPUM68KState *env)
BASE(nop, 4e71, ffff);
INSN(rtd, 4e74, ffff, RTD);
BASE(rts, 4e75, ffff);
+ INSN(rtr, 4e77, ffff, M68000);
BASE(jump, 4e80, ffc0);
BASE(jump, 4ec0, ffc0);
INSN(addsubq, 5000, f080, M68000);
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index 0b682a1f94..429de28494 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -2175,14 +2175,17 @@ static int bcd_cmp_mag(ppc_avr_t *a, ppc_avr_t *b)
return 0;
}
-static void bcd_add_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid,
+static int bcd_add_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid,
int *overflow)
{
int carry = 0;
int i;
+ int is_zero = 1;
+
for (i = 1; i <= 31; i++) {
uint8_t digit = bcd_get_digit(a, i, invalid) +
bcd_get_digit(b, i, invalid) + carry;
+ is_zero &= (digit == 0);
if (digit > 9) {
carry = 1;
digit -= 10;
@@ -2194,6 +2197,7 @@ static void bcd_add_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid,
}
*overflow = carry;
+ return is_zero;
}
static void bcd_sub_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid,
@@ -2225,14 +2229,15 @@ uint32_t helper_bcdadd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
int sgnb = bcd_get_sgn(b);
int invalid = (sgna == 0) || (sgnb == 0);
int overflow = 0;
+ int zero = 0;
uint32_t cr = 0;
ppc_avr_t result = { .u64 = { 0, 0 } };
if (!invalid) {
if (sgna == sgnb) {
result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(sgna, ps);
- bcd_add_mag(&result, a, b, &invalid, &overflow);
- cr = bcd_cmp_zero(&result);
+ zero = bcd_add_mag(&result, a, b, &invalid, &overflow);
+ cr = (sgna > 0) ? CRF_GT : CRF_LT;
} else {
int magnitude = bcd_cmp_mag(a, b);
if (magnitude > 0) {
@@ -2255,6 +2260,8 @@ uint32_t helper_bcdadd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
cr = CRF_SO;
} else if (overflow) {
cr |= CRF_SO;
+ } else if (zero) {
+ cr |= CRF_EQ;
}
*r = result;
diff --git a/target/ppc/translate_init.c.inc b/target/ppc/translate_init.c.inc
index 108ff2be2b..c03a7c4f52 100644
--- a/target/ppc/translate_init.c.inc
+++ b/target/ppc/translate_init.c.inc
@@ -566,35 +566,71 @@ static void spr_write_601_ubatl(DisasContext *ctx, int sprn, int gprn)
#if !defined(CONFIG_USER_ONLY)
static void spr_read_40x_pit(DisasContext *ctx, int gprn, int sprn)
{
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
gen_helper_load_40x_pit(cpu_gpr[gprn], cpu_env);
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_stop_exception(ctx);
+ }
}
static void spr_write_40x_pit(DisasContext *ctx, int sprn, int gprn)
{
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
gen_helper_store_40x_pit(cpu_env, cpu_gpr[gprn]);
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_stop_exception(ctx);
+ }
}
static void spr_write_40x_dbcr0(DisasContext *ctx, int sprn, int gprn)
{
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
gen_store_spr(sprn, cpu_gpr[gprn]);
gen_helper_store_40x_dbcr0(cpu_env, cpu_gpr[gprn]);
/* We must stop translation as we may have rebooted */
gen_stop_exception(ctx);
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_stop_exception(ctx);
+ }
}
static void spr_write_40x_sler(DisasContext *ctx, int sprn, int gprn)
{
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
gen_helper_store_40x_sler(cpu_env, cpu_gpr[gprn]);
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_stop_exception(ctx);
+ }
}
static void spr_write_booke_tcr(DisasContext *ctx, int sprn, int gprn)
{
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
gen_helper_store_booke_tcr(cpu_env, cpu_gpr[gprn]);
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_stop_exception(ctx);
+ }
}
static void spr_write_booke_tsr(DisasContext *ctx, int sprn, int gprn)
{
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_io_start();
+ }
gen_helper_store_booke_tsr(cpu_env, cpu_gpr[gprn]);
+ if (tb_cflags(ctx->base.tb) & CF_USE_ICOUNT) {
+ gen_stop_exception(ctx);
+ }
}
#endif
diff --git a/tests/tcg/configure.sh b/tests/tcg/configure.sh
index 36b8a73a54..ce304f4933 100755
--- a/tests/tcg/configure.sh
+++ b/tests/tcg/configure.sh
@@ -251,6 +251,12 @@ for target in $target_list; do
echo "CROSS_CC_HAS_ARMV8_MTE=y" >> $config_target_mak
fi
;;
+ ppc*)
+ if do_compiler "$target_compiler" $target_compiler_cflags \
+ -mpower8-vector -o $TMPE $TMPC; then
+ echo "CROSS_CC_HAS_POWER8_VECTOR=y" >> $config_target_mak
+ fi
+ ;;
esac
enabled_cross_compilers="$enabled_cross_compilers $target_compiler"
diff --git a/tests/tcg/ppc64/Makefile.target b/tests/tcg/ppc64/Makefile.target
new file mode 100644
index 0000000000..0c6a4585fc
--- /dev/null
+++ b/tests/tcg/ppc64/Makefile.target
@@ -0,0 +1,13 @@
+# -*- Mode: makefile -*-
+#
+# ppc64 specific tweaks
+
+VPATH += $(SRC_PATH)/tests/tcg/ppc64
+VPATH += $(SRC_PATH)/tests/tcg/ppc64le
+
+ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_POWER8_VECTOR),)
+PPC64_TESTS=bcdsub
+endif
+bcdsub: CFLAGS += -mpower8-vector
+
+TESTS += $(PPC64_TESTS)
diff --git a/tests/tcg/ppc64le/Makefile.target b/tests/tcg/ppc64le/Makefile.target
new file mode 100644
index 0000000000..1acfcff94a
--- /dev/null
+++ b/tests/tcg/ppc64le/Makefile.target
@@ -0,0 +1,12 @@
+# -*- Mode: makefile -*-
+#
+# ppc64le specific tweaks
+
+VPATH += $(SRC_PATH)/tests/tcg/ppc64le
+
+ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_POWER8_VECTOR),)
+PPC64LE_TESTS=bcdsub
+endif
+bcdsub: CFLAGS += -mpower8-vector
+
+TESTS += $(PPC64LE_TESTS)
diff --git a/tests/tcg/ppc64le/bcdsub.c b/tests/tcg/ppc64le/bcdsub.c
new file mode 100644
index 0000000000..8c188cae6d
--- /dev/null
+++ b/tests/tcg/ppc64le/bcdsub.c
@@ -0,0 +1,130 @@
+#include <assert.h>
+#include <unistd.h>
+#include <signal.h>
+
+#define CRF_LT (1 << 3)
+#define CRF_GT (1 << 2)
+#define CRF_EQ (1 << 1)
+#define CRF_SO (1 << 0)
+#define UNDEF 0
+
+#define BCDSUB(vra, vrb, ps) \
+ asm ("bcdsub. %1,%2,%3,%4;" \
+ "mfocrf %0,0b10;" \
+ : "=r" (cr), "=v" (vrt) \
+ : "v" (vra), "v" (vrb), "i" (ps) \
+ : );
+
+#define TEST(vra, vrb, ps, exp_res, exp_cr6) \
+ do { \
+ __int128 vrt = 0; \
+ int cr = 0; \
+ BCDSUB(vra, vrb, ps); \
+ if (exp_res) \
+ assert(vrt == exp_res); \
+ assert((cr >> 4) == exp_cr6); \
+ } while (0)
+
+
+/*
+ * Unbounded result is equal to zero:
+ * sign = (PS) ? 0b1111 : 0b1100
+ * CR6 = 0b0010
+ */
+void test_bcdsub_eq(void)
+{
+ __int128 a, b;
+
+ /* maximum positive BCD value */
+ a = b = (((__int128) 0x9999999999999999) << 64 | 0x999999999999999c);
+
+ TEST(a, b, 0, 0xc, CRF_EQ);
+ TEST(a, b, 1, 0xf, CRF_EQ);
+}
+
+/*
+ * Unbounded result is greater than zero:
+ * sign = (PS) ? 0b1111 : 0b1100
+ * CR6 = (overflow) ? 0b0101 : 0b0100
+ */
+void test_bcdsub_gt(void)
+{
+ __int128 a, b, c;
+
+ /* maximum positive BCD value */
+ a = (((__int128) 0x9999999999999999) << 64 | 0x999999999999999c);
+
+ /* negative one BCD value */
+ b = (__int128) 0x1d;
+
+ TEST(a, b, 0, 0xc, (CRF_GT | CRF_SO));
+ TEST(a, b, 1, 0xf, (CRF_GT | CRF_SO));
+
+ c = (((__int128) 0x9999999999999999) << 64 | 0x999999999999998c);
+
+ TEST(c, b, 0, a, CRF_GT);
+ TEST(c, b, 1, (a | 0x3), CRF_GT);
+}
+
+/*
+ * Unbounded result is less than zero:
+ * sign = 0b1101
+ * CR6 = (overflow) ? 0b1001 : 0b1000
+ */
+void test_bcdsub_lt(void)
+{
+ __int128 a, b;
+
+ /* positive zero BCD value */
+ a = (__int128) 0xc;
+
+ /* positive one BCD value */
+ b = (__int128) 0x1c;
+
+ TEST(a, b, 0, 0x1d, CRF_LT);
+ TEST(a, b, 1, 0x1d, CRF_LT);
+
+ /* maximum negative BCD value */
+ a = (((__int128) 0x9999999999999999) << 64 | 0x999999999999999d);
+
+ /* positive one BCD value */
+ b = (__int128) 0x1c;
+
+ TEST(a, b, 0, 0xd, (CRF_LT | CRF_SO));
+ TEST(a, b, 1, 0xd, (CRF_LT | CRF_SO));
+}
+
+void test_bcdsub_invalid(void)
+{
+ __int128 a, b;
+
+ /* positive one BCD value */
+ a = (__int128) 0x1c;
+ b = 0xf00;
+
+ TEST(a, b, 0, UNDEF, CRF_SO);
+ TEST(a, b, 1, UNDEF, CRF_SO);
+
+ TEST(b, a, 0, UNDEF, CRF_SO);
+ TEST(b, a, 1, UNDEF, CRF_SO);
+
+ a = 0xbad;
+
+ TEST(a, b, 0, UNDEF, CRF_SO);
+ TEST(a, b, 1, UNDEF, CRF_SO);
+}
+
+int main(void)
+{
+ struct sigaction action;
+
+ action.sa_handler = _exit;
+ sigaction(SIGABRT, &action, NULL);
+
+ test_bcdsub_eq();
+ test_bcdsub_gt();
+ test_bcdsub_lt();
+ test_bcdsub_invalid();
+
+ return 0;
+}
diff --git a/ui/cocoa.m b/ui/cocoa.m
index f27beb30e6..a7848ae0a3 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -30,6 +30,7 @@
#include "qemu-common.h"
#include "ui/console.h"
#include "ui/input.h"
+#include "ui/kbd-state.h"
#include "sysemu/sysemu.h"
#include "sysemu/runstate.h"
#include "sysemu/cpu-throttle.h"
@@ -39,6 +40,7 @@
#include "qapi/qapi-commands-misc.h"
#include "sysemu/blockdev.h"
#include "qemu-version.h"
+#include "qemu/cutils.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
#include <Carbon/Carbon.h>
@@ -80,7 +82,7 @@ static void cocoa_switch(DisplayChangeListener *dcl,
static void cocoa_refresh(DisplayChangeListener *dcl);
-NSWindow *normalWindow, *about_window;
+static NSWindow *normalWindow, *about_window;
static const DisplayChangeListenerOps dcl_ops = {
.dpy_name = "cocoa",
.dpy_gfx_update = cocoa_update,
@@ -93,11 +95,11 @@ static DisplayChangeListener dcl = {
static int last_buttons;
static int cursor_hide = 1;
-int gArgc;
-char **gArgv;
-bool stretch_video;
-NSTextField *pauseLabel;
-NSArray * supportedImageFileTypes;
+static int gArgc;
+static char **gArgv;
+static bool stretch_video;
+static NSTextField *pauseLabel;
+static NSArray * supportedImageFileTypes;
static QemuSemaphore display_init_sem;
static QemuSemaphore app_started_sem;
@@ -135,7 +137,7 @@ static bool bool_with_iothread_lock(BoolCodeBlock block)
}
// Mac to QKeyCode conversion
-const int mac_to_qkeycode_map[] = {
+static const int mac_to_qkeycode_map[] = {
[kVK_ANSI_A] = Q_KEY_CODE_A,
[kVK_ANSI_B] = Q_KEY_CODE_B,
[kVK_ANSI_C] = Q_KEY_CODE_C,
@@ -189,14 +191,6 @@ const int mac_to_qkeycode_map[] = {
[kVK_ANSI_Comma] = Q_KEY_CODE_COMMA,
[kVK_ANSI_Period] = Q_KEY_CODE_DOT,
[kVK_ANSI_Slash] = Q_KEY_CODE_SLASH,
- [kVK_Shift] = Q_KEY_CODE_SHIFT,
- [kVK_RightShift] = Q_KEY_CODE_SHIFT_R,
- [kVK_Control] = Q_KEY_CODE_CTRL,
- [kVK_RightControl] = Q_KEY_CODE_CTRL_R,
- [kVK_Option] = Q_KEY_CODE_ALT,
- [kVK_RightOption] = Q_KEY_CODE_ALT_R,
- [kVK_Command] = Q_KEY_CODE_META_L,
- [0x36] = Q_KEY_CODE_META_R, /* There is no kVK_RightCommand */
[kVK_Space] = Q_KEY_CODE_SPC,
[kVK_ANSI_Keypad0] = Q_KEY_CODE_KP_0,
@@ -306,11 +300,10 @@ static void handleAnyDeviceErrors(Error * err)
NSWindow *fullScreenWindow;
float cx,cy,cw,ch,cdx,cdy;
pixman_image_t *pixman_image;
- BOOL modifiers_state[256];
+ QKbdState *kbd;
BOOL isMouseGrabbed;
BOOL isFullscreen;
BOOL isAbsoluteEnabled;
- BOOL isMouseDeassociated;
}
- (void) switchSurface:(pixman_image_t *)image;
- (void) grabMouse;
@@ -327,14 +320,9 @@ static void handleAnyDeviceErrors(Error * err)
* isMouseGrabbed tracks whether GUI events are directed to the guest;
* it controls whether special keys like Cmd get sent to the guest,
* and whether we capture the mouse when in non-absolute mode.
- * isMouseDeassociated tracks whether we've told MacOSX to disassociate
- * the mouse and mouse cursor position by calling
- * CGAssociateMouseAndMouseCursorPosition(FALSE)
- * (which basically happens if we grab in non-absolute mode).
*/
- (BOOL) isMouseGrabbed;
- (BOOL) isAbsoluteEnabled;
-- (BOOL) isMouseDeassociated;
- (float) cdx;
- (float) cdy;
- (QEMUScreen) gscreen;
@@ -353,6 +341,7 @@ QemuCocoaView *cocoaView;
screen.width = frameRect.size.width;
screen.height = frameRect.size.height;
+ kbd = qkbd_state_init(dcl.con);
}
return self;
@@ -366,6 +355,7 @@ QemuCocoaView *cocoaView;
pixman_image_unref(pixman_image);
}
+ qkbd_state_free(kbd);
[super dealloc];
}
@@ -463,13 +453,8 @@ QemuCocoaView *cocoaView;
DIV_ROUND_UP(bitsPerPixel, 8) * 2, //bitsPerComponent
bitsPerPixel, //bitsPerPixel
stride, //bytesPerRow
-#ifdef __LITTLE_ENDIAN__
- CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), //colorspace for OS X >= 10.4
- kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst,
-#else
- CGColorSpaceCreateDeviceRGB(), //colorspace for OS X < 10.4 (actually ppc)
- kCGImageAlphaNoneSkipFirst, //bitmapInfo
-#endif
+ CGColorSpaceCreateWithName(kCGColorSpaceSRGB), //colorspace
+ kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst, //bitmapInfo
dataProviderRef, //provider
NULL, //decode
0, //interpolate
@@ -608,19 +593,8 @@ QemuCocoaView *cocoaView;
}
}
-- (void) toggleModifier: (int)keycode {
- // Toggle the stored state.
- modifiers_state[keycode] = !modifiers_state[keycode];
- // Send a keyup or keydown depending on the state.
- qemu_input_event_send_key_qcode(dcl.con, keycode, modifiers_state[keycode]);
-}
-
-- (void) toggleStatefulModifier: (int)keycode {
- // Toggle the stored state.
- modifiers_state[keycode] = !modifiers_state[keycode];
- // Generate keydown and keyup.
- qemu_input_event_send_key_qcode(dcl.con, keycode, true);
- qemu_input_event_send_key_qcode(dcl.con, keycode, false);
+- (void) toggleKey: (int)keycode {
+ qkbd_state_key_event(kbd, keycode, !qkbd_state_key_get(kbd, keycode));
}
// Does the work of sending input to the monitor
@@ -714,57 +688,86 @@ QemuCocoaView *cocoaView;
static bool switched_to_fullscreen = false;
// Location of event in virtual screen coordinates
NSPoint p = [self screenLocationOfEvent:event];
+ NSUInteger modifiers = [event modifierFlags];
+
+ // emulate caps lock keydown and keyup
+ if (!!(modifiers & NSEventModifierFlagCapsLock) !=
+ qkbd_state_modifier_get(kbd, QKBD_MOD_CAPSLOCK)) {
+ qkbd_state_key_event(kbd, Q_KEY_CODE_CAPS_LOCK, true);
+ qkbd_state_key_event(kbd, Q_KEY_CODE_CAPS_LOCK, false);
+ }
+
+ if (!(modifiers & NSEventModifierFlagShift)) {
+ qkbd_state_key_event(kbd, Q_KEY_CODE_SHIFT, false);
+ qkbd_state_key_event(kbd, Q_KEY_CODE_SHIFT_R, false);
+ }
+ if (!(modifiers & NSEventModifierFlagControl)) {
+ qkbd_state_key_event(kbd, Q_KEY_CODE_CTRL, false);
+ qkbd_state_key_event(kbd, Q_KEY_CODE_CTRL_R, false);
+ }
+ if (!(modifiers & NSEventModifierFlagOption)) {
+ qkbd_state_key_event(kbd, Q_KEY_CODE_ALT, false);
+ qkbd_state_key_event(kbd, Q_KEY_CODE_ALT_R, false);
+ }
+ if (!(modifiers & NSEventModifierFlagCommand)) {
+ qkbd_state_key_event(kbd, Q_KEY_CODE_META_L, false);
+ qkbd_state_key_event(kbd, Q_KEY_CODE_META_R, false);
+ }
switch ([event type]) {
case NSEventTypeFlagsChanged:
- if ([event keyCode] == 0) {
- // When the Cocoa keyCode is zero that means keys should be
- // synthesized based on the values in in the eventModifiers
- // bitmask.
-
- if (qemu_console_is_graphic(NULL)) {
- NSUInteger modifiers = [event modifierFlags];
+ switch ([event keyCode]) {
+ case kVK_Shift:
+ if (!!(modifiers & NSEventModifierFlagShift)) {
+ [self toggleKey:Q_KEY_CODE_SHIFT];
+ }
+ break;
- if (!!(modifiers & NSEventModifierFlagCapsLock) != !!modifiers_state[Q_KEY_CODE_CAPS_LOCK]) {
- [self toggleStatefulModifier:Q_KEY_CODE_CAPS_LOCK];
+ case kVK_RightShift:
+ if (!!(modifiers & NSEventModifierFlagShift)) {
+ [self toggleKey:Q_KEY_CODE_SHIFT_R];
}
- if (!!(modifiers & NSEventModifierFlagShift) != !!modifiers_state[Q_KEY_CODE_SHIFT]) {
- [self toggleModifier:Q_KEY_CODE_SHIFT];
+ break;
+
+ case kVK_Control:
+ if (!!(modifiers & NSEventModifierFlagControl)) {
+ [self toggleKey:Q_KEY_CODE_CTRL];
}
- if (!!(modifiers & NSEventModifierFlagControl) != !!modifiers_state[Q_KEY_CODE_CTRL]) {
- [self toggleModifier:Q_KEY_CODE_CTRL];
+ break;
+
+ case kVK_RightControl:
+ if (!!(modifiers & NSEventModifierFlagControl)) {
+ [self toggleKey:Q_KEY_CODE_CTRL_R];
}
- if (!!(modifiers & NSEventModifierFlagOption) != !!modifiers_state[Q_KEY_CODE_ALT]) {
- [self toggleModifier:Q_KEY_CODE_ALT];
+ break;
+
+ case kVK_Option:
+ if (!!(modifiers & NSEventModifierFlagOption)) {
+ [self toggleKey:Q_KEY_CODE_ALT];
}
- if (!!(modifiers & NSEventModifierFlagCommand) != !!modifiers_state[Q_KEY_CODE_META_L]) {
- [self toggleModifier:Q_KEY_CODE_META_L];
+ break;
+
+ case kVK_RightOption:
+ if (!!(modifiers & NSEventModifierFlagOption)) {
+ [self toggleKey:Q_KEY_CODE_ALT_R];
}
- }
- } else {
- keycode = cocoa_keycode_to_qemu([event keyCode]);
- }
+ break;
- if ((keycode == Q_KEY_CODE_META_L || keycode == Q_KEY_CODE_META_R)
- && !isMouseGrabbed) {
- /* Don't pass command key changes to guest unless mouse is grabbed */
- keycode = 0;
- }
+ /* Don't pass command key changes to guest unless mouse is grabbed */
+ case kVK_Command:
+ if (isMouseGrabbed &&
+ !!(modifiers & NSEventModifierFlagCommand)) {
+ [self toggleKey:Q_KEY_CODE_META_L];
+ }
+ break;
- if (keycode) {
- // emulate caps lock and num lock keydown and keyup
- if (keycode == Q_KEY_CODE_CAPS_LOCK ||
- keycode == Q_KEY_CODE_NUM_LOCK) {
- [self toggleStatefulModifier:keycode];
- } else if (qemu_console_is_graphic(NULL)) {
- if (switched_to_fullscreen) {
- switched_to_fullscreen = false;
- } else {
- [self toggleModifier:keycode];
+ case kVK_RightCommand:
+ if (isMouseGrabbed &&
+ !!(modifiers & NSEventModifierFlagCommand)) {
+ [self toggleKey:Q_KEY_CODE_META_R];
}
- }
+ break;
}
-
break;
case NSEventTypeKeyDown:
keycode = cocoa_keycode_to_qemu([event keyCode]);
@@ -804,7 +807,7 @@ QemuCocoaView *cocoaView;
}
if (qemu_console_is_graphic(NULL)) {
- qemu_input_event_send_key_qcode(dcl.con, keycode, true);
+ qkbd_state_key_event(kbd, keycode, true);
} else {
[self handleMonitorInput: event];
}
@@ -819,7 +822,7 @@ QemuCocoaView *cocoaView;
}
if (qemu_console_is_graphic(NULL)) {
- qemu_input_event_send_key_qcode(dcl.con, keycode, false);
+ qkbd_state_key_event(kbd, keycode, false);
}
break;
case NSEventTypeMouseMoved:
@@ -963,10 +966,7 @@ QemuCocoaView *cocoaView;
[normalWindow setTitle:@"QEMU - (Press ctrl + alt + g to release Mouse)"];
}
[self hideCursor];
- if (!isAbsoluteEnabled) {
- isMouseDeassociated = TRUE;
- CGAssociateMouseAndMouseCursorPosition(FALSE);
- }
+ CGAssociateMouseAndMouseCursorPosition(isAbsoluteEnabled);
isMouseGrabbed = TRUE; // while isMouseGrabbed = TRUE, QemuCocoaApp sends all events to [cocoaView handleEvent:]
}
@@ -981,17 +981,18 @@ QemuCocoaView *cocoaView;
[normalWindow setTitle:@"QEMU"];
}
[self unhideCursor];
- if (isMouseDeassociated) {
- CGAssociateMouseAndMouseCursorPosition(TRUE);
- isMouseDeassociated = FALSE;
- }
+ CGAssociateMouseAndMouseCursorPosition(TRUE);
isMouseGrabbed = FALSE;
}
-- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled {isAbsoluteEnabled = tIsAbsoluteEnabled;}
+- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled {
+ isAbsoluteEnabled = tIsAbsoluteEnabled;
+ if (isMouseGrabbed) {
+ CGAssociateMouseAndMouseCursorPosition(isAbsoluteEnabled);
+ }
+}
- (BOOL) isMouseGrabbed {return isMouseGrabbed;}
- (BOOL) isAbsoluteEnabled {return isAbsoluteEnabled;}
-- (BOOL) isMouseDeassociated {return isMouseDeassociated;}
- (float) cdx {return cdx;}
- (float) cdy {return cdy;}
- (QEMUScreen) gscreen {return screen;}
@@ -1003,17 +1004,8 @@ QemuCocoaView *cocoaView;
*/
- (void) raiseAllKeys
{
- const int max_index = ARRAY_SIZE(modifiers_state);
-
with_iothread_lock(^{
- int index;
-
- for (index = 0; index < max_index; index++) {
- if (modifiers_state[index]) {
- modifiers_state[index] = 0;
- qemu_input_event_send_key_qcode(dcl.con, index, false);
- }
- }
+ qkbd_state_lift_all_keys(kbd);
});
}
@end
@@ -1390,37 +1382,33 @@ QemuCocoaView *cocoaView;
y = about_height - picture_height - 10;
NSRect picture_rect = NSMakeRect(x, y, picture_width, picture_height);
- /* Get the path to the QEMU binary */
- NSString *binary_name = [NSString stringWithCString: gArgv[0]
- encoding: NSASCIIStringEncoding];
- binary_name = [binary_name lastPathComponent];
- NSString *program_path = [[NSString alloc] initWithFormat: @"%@/%@",
- [[NSBundle mainBundle] bundlePath], binary_name];
-
/* Make the picture of QEMU */
NSImageView *picture_view = [[NSImageView alloc] initWithFrame:
picture_rect];
- NSImage *qemu_image = [[NSWorkspace sharedWorkspace] iconForFile:
- program_path];
+ char *qemu_image_path_c = get_relocated_path(CONFIG_QEMU_ICONDIR "/hicolor/512x512/apps/qemu.png");
+ NSString *qemu_image_path = [NSString stringWithUTF8String:qemu_image_path_c];
+ g_free(qemu_image_path_c);
+ NSImage *qemu_image = [[NSImage alloc] initWithContentsOfFile:qemu_image_path];
[picture_view setImage: qemu_image];
[picture_view setImageScaling: NSImageScaleProportionallyUpOrDown];
[superView addSubview: picture_view];
/* Make the name label */
- x = 0;
- y = y - 25;
- int name_width = about_width, name_height = 20;
- NSRect name_rect = NSMakeRect(x, y, name_width, name_height);
- NSTextField *name_label = [[NSTextField alloc] initWithFrame: name_rect];
- [name_label setEditable: NO];
- [name_label setBezeled: NO];
- [name_label setDrawsBackground: NO];
- [name_label setAlignment: NSTextAlignmentCenter];
- NSString *qemu_name = [[NSString alloc] initWithCString: gArgv[0]
- encoding: NSASCIIStringEncoding];
- qemu_name = [qemu_name lastPathComponent];
- [name_label setStringValue: qemu_name];
- [superView addSubview: name_label];
+ NSBundle *bundle = [NSBundle mainBundle];
+ if (bundle) {
+ x = 0;
+ y = y - 25;
+ int name_width = about_width, name_height = 20;
+ NSRect name_rect = NSMakeRect(x, y, name_width, name_height);
+ NSTextField *name_label = [[NSTextField alloc] initWithFrame: name_rect];
+ [name_label setEditable: NO];
+ [name_label setBezeled: NO];
+ [name_label setDrawsBackground: NO];
+ [name_label setAlignment: NSTextAlignmentCenter];
+ NSString *qemu_name = [[bundle executablePath] lastPathComponent];
+ [name_label setStringValue: qemu_name];
+ [superView addSubview: name_label];
+ }
/* Set the version label's attributes */
x = 0;
diff --git a/ui/gtk.c b/ui/gtk.c
index 916056d89e..1ea1253528 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -547,9 +547,7 @@ static void gd_switch(DisplayChangeListener *dcl,
VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
bool resized = true;
- trace_gd_switch(vc->label,
- surface ? surface_width(surface) : 0,
- surface ? surface_height(surface) : 0);
+ trace_gd_switch(vc->label, surface_width(surface), surface_height(surface));
if (vc->gfx.surface) {
cairo_surface_destroy(vc->gfx.surface);
@@ -560,7 +558,7 @@ static void gd_switch(DisplayChangeListener *dcl,
vc->gfx.convert = NULL;
}
- if (vc->gfx.ds && surface &&
+ if (vc->gfx.ds &&
surface_width(vc->gfx.ds) == surface_width(surface) &&
surface_height(vc->gfx.ds) == surface_height(surface)) {
resized = false;
diff --git a/util/qemu-timer.c b/util/qemu-timer.c
index f36c75e594..be529c1f65 100644
--- a/util/qemu-timer.c
+++ b/util/qemu-timer.c
@@ -242,6 +242,19 @@ int64_t timerlist_deadline_ns(QEMUTimerList *timer_list)
return delta;
}
+/*
+ * Returns the time remaining for the deadline, in ms.
+ */
+int64_t timer_deadline_ms(QEMUTimer *timer)
+{
+ if (timer_pending(timer)) {
+ return qemu_timeout_ns_to_ms(timer->expire_time) -
+ qemu_clock_get_ms(timer->timer_list->clock->type);
+ }
+
+ return 0;
+}
+
/* Calculate the soonest deadline across all timerlists attached
* to the clock. This is used for the icount timeout so we
* ignore whether or not the clock should be used in deadline