diff options
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 Binary files differindex 448dcada36..3f3918a9e1 100644 --- a/pc-bios/slof.bin +++ b/pc-bios/slof.bin 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; @@ -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 |