summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--backends/baum.c4
-rwxr-xr-xconfigure100
-rw-r--r--default-configs/ppc-softmmu.mak1
-rw-r--r--hw/arm/musicpal.c2
-rw-r--r--hw/core/loader.c30
-rw-r--r--hw/core/qdev.c20
-rw-r--r--hw/display/blizzard.c2
-rw-r--r--hw/display/cg3.c2
-rw-r--r--hw/display/cirrus_vga.c4
-rw-r--r--hw/display/exynos4210_fimd.c2
-rw-r--r--hw/display/g364fb.c2
-rw-r--r--hw/display/jazz_led.c2
-rw-r--r--hw/display/milkymist-vgafb.c2
-rw-r--r--hw/display/omap_lcdc.c2
-rw-r--r--hw/display/pl110.c2
-rw-r--r--hw/display/pxa2xx_lcd.c2
-rw-r--r--hw/display/qxl.c4
-rw-r--r--hw/display/sm501.c2
-rw-r--r--hw/display/ssd0303.c2
-rw-r--r--hw/display/ssd0323.c2
-rw-r--r--hw/display/tc6393xb.c2
-rw-r--r--hw/display/tcx.c4
-rw-r--r--hw/display/vga-isa-mm.c2
-rw-r--r--hw/display/vga-isa.c2
-rw-r--r--hw/display/vga-pci.c2
-rw-r--r--hw/display/vmware_vga.c2
-rw-r--r--hw/display/xenfb.c2
-rw-r--r--hw/i386/pc_piix.c8
-rw-r--r--hw/intc/openpic_kvm.c2
-rw-r--r--hw/intc/xics.c15
-rw-r--r--hw/intc/xics_kvm.c10
-rw-r--r--hw/moxie/moxiesim.c2
-rw-r--r--hw/net/Makefile.objs3
-rw-r--r--hw/net/fsl_etsec/etsec.c465
-rw-r--r--hw/net/fsl_etsec/etsec.h174
-rw-r--r--hw/net/fsl_etsec/miim.c146
-rw-r--r--hw/net/fsl_etsec/registers.c295
-rw-r--r--hw/net/fsl_etsec/registers.h320
-rw-r--r--hw/net/fsl_etsec/rings.c650
-rw-r--r--hw/net/spapr_llan.c2
-rw-r--r--hw/ppc/e500.c7
-rw-r--r--hw/ppc/ppc.c22
-rw-r--r--hw/ppc/spapr.c56
-rw-r--r--hw/ppc/spapr_hcall.c87
-rw-r--r--hw/ppc/spapr_iommu.c37
-rw-r--r--hw/ppc/spapr_pci.c15
-rw-r--r--hw/ppc/spapr_rtas.c14
-rw-r--r--hw/ppc/virtex_ml507.c34
-rw-r--r--hw/s390x/css.c10
-rw-r--r--hw/s390x/css.h2
-rw-r--r--hw/s390x/ipl.c4
-rw-r--r--hw/s390x/virtio-ccw.c102
-rw-r--r--hw/s390x/virtio-ccw.h4
-rw-r--r--hw/scsi/spapr_vscsi.c60
-rw-r--r--hw/unicore32/puv3.c2
-rw-r--r--include/hw/boards.h6
-rw-r--r--include/hw/elf_ops.h19
-rw-r--r--include/hw/loader.h6
-rw-r--r--include/hw/qdev-core.h2
-rw-r--r--include/hw/xen/xen.h3
-rw-r--r--include/qemu/host-utils.h28
-rw-r--r--include/sysemu/kvm.h3
-rw-r--r--include/sysemu/qemumachine.h16
-rw-r--r--include/sysemu/qtest.h3
-rw-r--r--include/ui/console.h33
-rw-r--r--include/ui/input.h56
-rw-r--r--kvm-all.c17
-rw-r--r--kvm-stub.c3
-rw-r--r--linux-user/main.c18
-rw-r--r--monitor.c31
-rw-r--r--qapi-schema.json83
-rw-r--r--qtest.c2
-rw-r--r--target-ppc/STATUS9
-rw-r--r--target-ppc/cpu-models.c2
-rw-r--r--target-ppc/cpu-models.h1
-rw-r--r--target-ppc/cpu-qom.h2
-rw-r--r--target-ppc/cpu.h55
-rw-r--r--target-ppc/fpu_helper.c1294
-rw-r--r--target-ppc/helper.h207
-rw-r--r--target-ppc/int_helper.c1411
-rw-r--r--target-ppc/kvm.c117
-rw-r--r--target-ppc/kvm_ppc.h35
-rw-r--r--target-ppc/machine.c11
-rw-r--r--target-ppc/misc_helper.c4
-rw-r--r--target-ppc/mmu-hash64.c117
-rw-r--r--target-ppc/mmu-hash64.h47
-rw-r--r--target-ppc/mmu_helper.c3
-rw-r--r--target-ppc/translate.c1268
-rw-r--r--target-ppc/translate_init.c274
-rw-r--r--target-s390x/ioinst.h2
-rw-r--r--target-s390x/kvm.c8
-rw-r--r--trace-events13
-rw-r--r--ui/Makefile.objs6
-rw-r--r--ui/cocoa.m81
-rw-r--r--ui/console.c69
-rw-r--r--ui/curses.c47
-rw-r--r--ui/gtk.c77
-rw-r--r--ui/input-legacy.c453
-rw-r--r--ui/input.c682
-rw-r--r--ui/sdl.c114
-rw-r--r--ui/sdl2-keymap.h266
-rw-r--r--ui/sdl2.c829
-rw-r--r--ui/sdl_keysym.h3
-rw-r--r--ui/spice-input.c84
-rw-r--r--ui/vnc.c71
-rw-r--r--ui/vnc.h1
-rw-r--r--util/host-utils.c75
-rw-r--r--vl.c14
-rw-r--r--xen-all.c2
-rw-r--r--xen-stub.c2
111 files changed, 9324 insertions, 1516 deletions
diff --git a/Makefile b/Makefile
index ea6c71284b..bd9cd4fceb 100644
--- a/Makefile
+++ b/Makefile
@@ -399,7 +399,7 @@ endif
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(qemu_datadir)/keymaps"; \
done
for d in $(TARGET_DIRS); do \
- $(MAKE) -C $$d $@ || exit 1 ; \
+ $(MAKE) $(SUBDIR_MAKEFLAGS) TARGET_DIR=$$d/ -C $$d $@ || exit 1 ; \
done
# various test targets
diff --git a/backends/baum.c b/backends/baum.c
index 1132899026..665107fa9c 100644
--- a/backends/baum.c
+++ b/backends/baum.c
@@ -566,7 +566,7 @@ CharDriverState *chr_baum_init(void)
BaumDriverState *baum;
CharDriverState *chr;
brlapi_handle_t *handle;
-#ifdef CONFIG_SDL
+#if defined(CONFIG_SDL) && SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 0)
SDL_SysWMinfo info;
#endif
int tty;
@@ -595,7 +595,7 @@ CharDriverState *chr_baum_init(void)
goto fail;
}
-#ifdef CONFIG_SDL
+#if defined(CONFIG_SDL) && SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 0)
memset(&info, 0, sizeof(info));
SDL_VERSION(&info.version);
if (SDL_GetWMInfo(&info))
diff --git a/configure b/configure
index 6ccadc3343..8689435ccf 100755
--- a/configure
+++ b/configure
@@ -14,13 +14,14 @@ fi
TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c"
TMPB="qemu-conf-${RANDOM}-$$-${RANDOM}"
TMPO="${TMPDIR1}/${TMPB}.o"
+TMPCXX="${TMPDIR1}/${TMPB}.cxx"
TMPL="${TMPDIR1}/${TMPB}.lo"
TMPA="${TMPDIR1}/lib${TMPB}.la"
TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.exe"
# NB: do not call "exit" in the trap handler; this is buggy with some shells;
# see <1285349658-3122-1-git-send-email-loic.minier@linaro.org>
-trap "rm -f $TMPC $TMPO $TMPE" EXIT INT QUIT TERM
+trap "rm -f $TMPC $TMPO $TMPCXX $TMPE" EXIT INT QUIT TERM
rm -f config.log
# Print a helpful header at the top of config.log
@@ -54,10 +55,13 @@ error_exit() {
exit 1
}
-do_cc() {
- # Run the compiler, capturing its output to the log.
- echo $cc "$@" >> config.log
- $cc "$@" >> config.log 2>&1 || return $?
+do_compiler() {
+ # Run the compiler, capturing its output to the log. First argument
+ # is compiler binary to execute.
+ local compiler="$1"
+ shift
+ echo $compiler "$@" >> config.log
+ $compiler "$@" >> config.log 2>&1 || return $?
# Test passed. If this is an --enable-werror build, rerun
# the test with -Werror and bail out if it fails. This
# makes warning-generating-errors in configure test code
@@ -71,14 +75,39 @@ do_cc() {
return 0
;;
esac
- echo $cc -Werror "$@" >> config.log
- $cc -Werror "$@" >> config.log 2>&1 && return $?
+ echo $compiler -Werror "$@" >> config.log
+ $compiler -Werror "$@" >> config.log 2>&1 && return $?
error_exit "configure test passed without -Werror but failed with -Werror." \
"This is probably a bug in the configure script. The failing command" \
"will be at the bottom of config.log." \
"You can run configure with --disable-werror to bypass this check."
}
+do_cc() {
+ do_compiler "$cc" "$@"
+}
+
+do_cxx() {
+ do_compiler "$cxx" "$@"
+}
+
+update_cxxflags() {
+ # Set QEMU_CXXFLAGS from QEMU_CFLAGS by filtering out those
+ # options which some versions of GCC's C++ compiler complain about
+ # because they only make sense for C programs.
+ QEMU_CXXFLAGS=
+ for arg in $QEMU_CFLAGS; do
+ case $arg in
+ -Wstrict-prototypes|-Wmissing-prototypes|-Wnested-externs|\
+ -Wold-style-declaration|-Wold-style-definition|-Wredundant-decls)
+ ;;
+ *)
+ QEMU_CXXFLAGS=${QEMU_CXXFLAGS:+$QEMU_CXXFLAGS }$arg
+ ;;
+ esac
+ done
+}
+
compile_object() {
do_cc $QEMU_CFLAGS -c -o $TMPO $TMPC
}
@@ -207,6 +236,7 @@ fdt=""
netmap="no"
pixman=""
sdl=""
+sdlabi="1.2"
virtfs=""
vnc="yes"
sparse="no"
@@ -366,12 +396,13 @@ query_pkg_config() {
}
pkg_config=query_pkg_config
sdl_config="${SDL_CONFIG-${cross_prefix}sdl-config}"
+sdl2_config="${SDL2_CONFIG-${cross_prefix}sdl2-config}"
# If the user hasn't specified ARFLAGS, default to 'rv', just as make does.
ARFLAGS="${ARFLAGS-rv}"
# default flags for all hosts
-QEMU_CFLAGS="-fno-strict-aliasing $QEMU_CFLAGS"
+QEMU_CFLAGS="-fno-strict-aliasing -fno-common $QEMU_CFLAGS"
QEMU_CFLAGS="-Wall -Wundef -Wwrite-strings -Wmissing-prototypes $QEMU_CFLAGS"
QEMU_CFLAGS="-Wstrict-prototypes -Wredundant-decls $QEMU_CFLAGS"
QEMU_CFLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE $QEMU_CFLAGS"
@@ -775,6 +806,8 @@ for opt do
;;
--enable-sdl) sdl="yes"
;;
+ --with-sdlabi=*) sdlabi="$optarg"
+ ;;
--disable-qom-cast-debug) qom_cast_debug="no"
;;
--enable-qom-cast-debug) qom_cast_debug="yes"
@@ -1196,6 +1229,7 @@ Advanced options (experts only):
--disable-werror disable compilation abort on warning
--disable-sdl disable SDL
--enable-sdl enable SDL
+ --with-sdlabi select preferred SDL ABI 1.2 or 2.0
--disable-gtk disable gtk UI
--enable-gtk enable gtk UI
--disable-virtfs disable VirtFS
@@ -1335,6 +1369,19 @@ if test "$ARCH" = "unknown"; then
fi
fi
+# Consult white-list to determine whether to enable werror
+# by default. Only enable by default for git builds
+z_version=`cut -f3 -d. $source_path/VERSION`
+
+if test -z "$werror" ; then
+ if test -d "$source_path/.git" -a \
+ "$linux" = "yes" ; then
+ werror="yes"
+ else
+ werror="no"
+ fi
+fi
+
# check that the C compiler works.
cat > $TMPC <<EOF
int main(void) { return 0; }
@@ -1355,14 +1402,16 @@ EOF
compile_object
- cat > $TMPC <<EOF
+ cat > $TMPCXX <<EOF
extern "C" {
int c_function(void);
}
int c_function(void) { return 42; }
EOF
- if (cc=$cxx do_cc $QEMU_CFLAGS -o $TMPE $TMPC $TMPO $LDFLAGS); then
+ update_cxxflags
+
+ if do_cxx $QEMU_CXXFLAGS -o $TMPE $TMPCXX $TMPO $LDFLAGS; then
# C++ compiler $cxx works ok with C compiler $cc
:
else
@@ -1375,19 +1424,6 @@ else
cxx=
fi
-# Consult white-list to determine whether to enable werror
-# by default. Only enable by default for git builds
-z_version=`cut -f3 -d. $source_path/VERSION`
-
-if test -z "$werror" ; then
- if test -d "$source_path/.git" -a \
- "$linux" = "yes" ; then
- werror="yes"
- else
- werror="no"
- fi
-fi
-
gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits"
gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags"
gcc_flags="-Wmissing-include-dirs -Wempty-body -Wnested-externs $gcc_flags"
@@ -1955,12 +1991,22 @@ fi
# Look for sdl configuration program (pkg-config or sdl-config). Try
# sdl-config even without cross prefix, and favour pkg-config over sdl-config.
-if test "`basename $sdl_config`" != sdl-config && ! has ${sdl_config}; then
- sdl_config=sdl-config
+
+if test $sdlabi = "2.0"; then
+ sdl_config=$sdl2_config
+ sdlname=sdl2
+ sdlconfigname=sdl2_config
+else
+ sdlname=sdl
+ sdlconfigname=sdl_config
+fi
+
+if test "`basename $sdl_config`" != $sdlconfigname && ! has ${sdl_config}; then
+ sdl_config=$sdlconfigname
fi
-if $pkg_config sdl --exists; then
- sdlconfig="$pkg_config sdl"
+if $pkg_config $sdlname --exists; then
+ sdlconfig="$pkg_config $sdlname"
_sdlversion=`$sdlconfig --modversion 2>/dev/null | sed 's/[^0-9]//g'`
elif has ${sdl_config}; then
sdlconfig="$sdl_config"
diff --git a/default-configs/ppc-softmmu.mak b/default-configs/ppc-softmmu.mak
index e5f9d36913..07c51ced1f 100644
--- a/default-configs/ppc-softmmu.mak
+++ b/default-configs/ppc-softmmu.mak
@@ -47,4 +47,5 @@ CONFIG_E500=y
CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM))
# For PReP
CONFIG_MC146818RTC=y
+CONFIG_ETSEC=y
CONFIG_ISA_TESTDEV=y
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index cce7127598..d10b5dbb49 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -630,7 +630,7 @@ static int musicpal_lcd_init(SysBusDevice *sbd)
"musicpal-lcd", MP_LCD_SIZE);
sysbus_init_mmio(sbd, &s->iomem);
- s->con = graphic_console_init(dev, &musicpal_gfx_ops, s);
+ s->con = graphic_console_init(dev, 0, &musicpal_gfx_ops, s);
qemu_console_resize(s->con, 128*3, 64*3);
qdev_init_gpio_in(dev, musicpal_lcd_gpio_brightness_in, 3);
diff --git a/hw/core/loader.c b/hw/core/loader.c
index e1c3f3a860..b323c0c7b8 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -284,12 +284,30 @@ static void *load_at(int fd, int offset, int size)
#define SZ 64
#include "hw/elf_ops.h"
+const char *load_elf_strerror(int error)
+{
+ switch (error) {
+ case 0:
+ return "No error";
+ case ELF_LOAD_FAILED:
+ return "Failed to load ELF";
+ case ELF_LOAD_NOT_ELF:
+ return "The image is not ELF";
+ case ELF_LOAD_WRONG_ARCH:
+ return "The image is from incompatible architecture";
+ case ELF_LOAD_WRONG_ENDIAN:
+ return "The image has incorrect endianness";
+ default:
+ return "Unknown error";
+ }
+}
+
/* return < 0 if error, otherwise the number of bytes loaded in memory */
int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
uint64_t *highaddr, int big_endian, int elf_machine, int clear_lsb)
{
- int fd, data_order, target_data_order, must_swab, ret;
+ int fd, data_order, target_data_order, must_swab, ret = ELF_LOAD_FAILED;
uint8_t e_ident[EI_NIDENT];
fd = open(filename, O_RDONLY | O_BINARY);
@@ -302,8 +320,10 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
if (e_ident[0] != ELFMAG0 ||
e_ident[1] != ELFMAG1 ||
e_ident[2] != ELFMAG2 ||
- e_ident[3] != ELFMAG3)
+ e_ident[3] != ELFMAG3) {
+ ret = ELF_LOAD_NOT_ELF;
goto fail;
+ }
#ifdef HOST_WORDS_BIGENDIAN
data_order = ELFDATA2MSB;
#else
@@ -317,6 +337,7 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
}
if (target_data_order != e_ident[EI_DATA]) {
+ ret = ELF_LOAD_WRONG_ENDIAN;
goto fail;
}
@@ -329,12 +350,9 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
pentry, lowaddr, highaddr, elf_machine, clear_lsb);
}
- close(fd);
- return ret;
-
fail:
close(fd);
- return -1;
+ return ret;
}
static void bswap_uboot_header(uboot_image_header_t *hdr)
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index c0b857fbd4..380976a066 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -440,27 +440,33 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id)
static void qbus_realize(BusState *bus, DeviceState *parent, const char *name)
{
const char *typename = object_get_typename(OBJECT(bus));
+ BusClass *bc;
char *buf;
- int i,len;
+ int i, len, bus_id;
bus->parent = parent;
if (name) {
bus->name = g_strdup(name);
} else if (bus->parent && bus->parent->id) {
- /* parent device has id -> use it for bus name */
+ /* parent device has id -> use it plus parent-bus-id for bus name */
+ bus_id = bus->parent->num_child_bus;
+
len = strlen(bus->parent->id) + 16;
buf = g_malloc(len);
- snprintf(buf, len, "%s.%d", bus->parent->id, bus->parent->num_child_bus);
+ snprintf(buf, len, "%s.%d", bus->parent->id, bus_id);
bus->name = buf;
} else {
- /* no id -> use lowercase bus type for bus name */
+ /* no id -> use lowercase bus type plus global bus-id for bus name */
+ bc = BUS_GET_CLASS(bus);
+ bus_id = bc->automatic_ids++;
+
len = strlen(typename) + 16;
buf = g_malloc(len);
- len = snprintf(buf, len, "%s.%d", typename,
- bus->parent ? bus->parent->num_child_bus : 0);
- for (i = 0; i < len; i++)
+ len = snprintf(buf, len, "%s.%d", typename, bus_id);
+ for (i = 0; i < len; i++) {
buf[i] = qemu_tolower(buf[i]);
+ }
bus->name = buf;
}
diff --git a/hw/display/blizzard.c b/hw/display/blizzard.c
index 4a466c8323..55c0ddf00b 100644
--- a/hw/display/blizzard.c
+++ b/hw/display/blizzard.c
@@ -956,7 +956,7 @@ void *s1d13745_init(qemu_irq gpio_int)
s->fb = g_malloc(0x180000);
- s->con = graphic_console_init(NULL, &blizzard_ops, s);
+ s->con = graphic_console_init(NULL, 0, &blizzard_ops, s);
surface = qemu_console_surface(s->con);
switch (surface_bits_per_pixel(surface)) {
diff --git a/hw/display/cg3.c b/hw/display/cg3.c
index 6db8ca362a..a042b9ecbe 100644
--- a/hw/display/cg3.c
+++ b/hw/display/cg3.c
@@ -306,7 +306,7 @@ static void cg3_realizefn(DeviceState *dev, Error **errp)
sysbus_init_irq(sbd, &s->irq);
- s->con = graphic_console_init(DEVICE(dev), &cg3_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, &cg3_ops, s);
qemu_console_resize(s->con, s->width, s->height);
}
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index 3a8fc0bf8e..0d3127da21 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -2917,7 +2917,7 @@ static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp)
cirrus_init_common(&d->cirrus_vga, OBJECT(dev), CIRRUS_ID_CLGD5430, 0,
isa_address_space(isadev),
isa_address_space_io(isadev));
- s->con = graphic_console_init(dev, s->hw_ops, s);
+ s->con = graphic_console_init(dev, 0, s->hw_ops, s);
rom_add_vga(VGABIOS_CIRRUS_FILENAME);
/* XXX ISA-LFB support */
/* FIXME not qdev yet */
@@ -2963,7 +2963,7 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
vga_common_init(&s->vga, OBJECT(dev));
cirrus_init_common(s, OBJECT(dev), device_id, 1, pci_address_space(dev),
pci_address_space_io(dev));
- s->vga.con = graphic_console_init(DEVICE(dev), s->vga.hw_ops, &s->vga);
+ s->vga.con = graphic_console_init(DEVICE(dev), 0, s->vga.hw_ops, &s->vga);
/* setup PCI */
diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c
index 65cca1d707..9750330c25 100644
--- a/hw/display/exynos4210_fimd.c
+++ b/hw/display/exynos4210_fimd.c
@@ -1917,7 +1917,7 @@ static int exynos4210_fimd_init(SysBusDevice *dev)
memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_fimd_mmio_ops, s,
"exynos4210.fimd", FIMD_REGS_SIZE);
sysbus_init_mmio(dev, &s->iomem);
- s->console = graphic_console_init(DEVICE(dev), &exynos4210_fimd_ops, s);
+ s->console = graphic_console_init(DEVICE(dev), 0, &exynos4210_fimd_ops, s);
return 0;
}
diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c
index bc909bb3de..5c6a2d3605 100644
--- a/hw/display/g364fb.c
+++ b/hw/display/g364fb.c
@@ -484,7 +484,7 @@ static void g364fb_init(DeviceState *dev, G364State *s)
{
s->vram = g_malloc0(s->vram_size);
- s->con = graphic_console_init(dev, &g364fb_ops, s);
+ s->con = graphic_console_init(dev, 0, &g364fb_ops, s);
memory_region_init_io(&s->mem_ctrl, NULL, &g364fb_ctrl_ops, s, "ctrl", 0x180000);
memory_region_init_ram_ptr(&s->mem_vram, NULL, "vram",
diff --git a/hw/display/jazz_led.c b/hw/display/jazz_led.c
index 8407e6c2ef..f9e7d7c981 100644
--- a/hw/display/jazz_led.c
+++ b/hw/display/jazz_led.c
@@ -271,7 +271,7 @@ static int jazz_led_init(SysBusDevice *dev)
memory_region_init_io(&s->iomem, OBJECT(s), &led_ops, s, "led", 1);
sysbus_init_mmio(dev, &s->iomem);
- s->con = graphic_console_init(DEVICE(dev), &jazz_led_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, &jazz_led_ops, s);
return 0;
}
diff --git a/hw/display/milkymist-vgafb.c b/hw/display/milkymist-vgafb.c
index 5150cb48b7..603537aabb 100644
--- a/hw/display/milkymist-vgafb.c
+++ b/hw/display/milkymist-vgafb.c
@@ -290,7 +290,7 @@ static int milkymist_vgafb_init(SysBusDevice *dev)
"milkymist-vgafb", R_MAX * 4);
sysbus_init_mmio(dev, &s->regs_region);
- s->con = graphic_console_init(DEVICE(dev), &vgafb_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, &vgafb_ops, s);
return 0;
}
diff --git a/hw/display/omap_lcdc.c b/hw/display/omap_lcdc.c
index c3b9b68971..fda81baff0 100644
--- a/hw/display/omap_lcdc.c
+++ b/hw/display/omap_lcdc.c
@@ -406,7 +406,7 @@ struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem,
memory_region_init_io(&s->iomem, NULL, &omap_lcdc_ops, s, "omap.lcdc", 0x100);
memory_region_add_subregion(sysmem, base, &s->iomem);
- s->con = graphic_console_init(NULL, &omap_ops, s);
+ s->con = graphic_console_init(NULL, 0, &omap_ops, s);
return s;
}
diff --git a/hw/display/pl110.c b/hw/display/pl110.c
index ab689e9aae..c574cf1a81 100644
--- a/hw/display/pl110.c
+++ b/hw/display/pl110.c
@@ -464,7 +464,7 @@ static int pl110_initfn(SysBusDevice *sbd)
sysbus_init_mmio(sbd, &s->iomem);
sysbus_init_irq(sbd, &s->irq);
qdev_init_gpio_in(dev, pl110_mux_ctrl_set, 1);
- s->con = graphic_console_init(dev, &pl110_gfx_ops, s);
+ s->con = graphic_console_init(dev, 0, &pl110_gfx_ops, s);
return 0;
}
diff --git a/hw/display/pxa2xx_lcd.c b/hw/display/pxa2xx_lcd.c
index 990931ae45..09cdf17ab9 100644
--- a/hw/display/pxa2xx_lcd.c
+++ b/hw/display/pxa2xx_lcd.c
@@ -1013,7 +1013,7 @@ PXA2xxLCDState *pxa2xx_lcdc_init(MemoryRegion *sysmem,
"pxa2xx-lcd-controller", 0x00100000);
memory_region_add_subregion(sysmem, base, &s->iomem);
- s->con = graphic_console_init(NULL, &pxa2xx_ops, s);
+ s->con = graphic_console_init(NULL, 0, &pxa2xx_ops, s);
surface = qemu_console_surface(s->con);
switch (surface_bits_per_pixel(surface)) {
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index 2a559ebcc9..47bbf1f1fe 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -2069,7 +2069,7 @@ static int qxl_init_primary(PCIDevice *dev)
portio_list_set_flush_coalesced(qxl_vga_port_list);
portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0);
- vga->con = graphic_console_init(DEVICE(dev), &qxl_ops, qxl);
+ vga->con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
qemu_spice_display_init_common(&qxl->ssd);
rc = qxl_init_common(qxl);
@@ -2094,7 +2094,7 @@ static int qxl_init_secondary(PCIDevice *dev)
qxl->vga.vram_size);
vmstate_register_ram(&qxl->vga.vram, &qxl->pci.qdev);
qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram);
- qxl->vga.con = graphic_console_init(DEVICE(dev), &qxl_ops, qxl);
+ qxl->vga.con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
return qxl_init_common(qxl);
}
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index 0b5f993594..eedf2d48e0 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -1449,5 +1449,5 @@ void sm501_init(MemoryRegion *address_space_mem, uint32_t base,
}
/* create qemu graphic console */
- s->con = graphic_console_init(DEVICE(dev), &sm501_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, &sm501_ops, s);
}
diff --git a/hw/display/ssd0303.c b/hw/display/ssd0303.c
index 89804e108b..c2eea04934 100644
--- a/hw/display/ssd0303.c
+++ b/hw/display/ssd0303.c
@@ -299,7 +299,7 @@ static int ssd0303_init(I2CSlave *i2c)
{
ssd0303_state *s = SSD0303(i2c);
- s->con = graphic_console_init(DEVICE(i2c), &ssd0303_ops, s);
+ s->con = graphic_console_init(DEVICE(i2c), 0, &ssd0303_ops, s);
qemu_console_resize(s->con, 96 * MAGNIFY, 16 * MAGNIFY);
return 0;
}
diff --git a/hw/display/ssd0323.c b/hw/display/ssd0323.c
index c3231c6116..46c3b40c79 100644
--- a/hw/display/ssd0323.c
+++ b/hw/display/ssd0323.c
@@ -342,7 +342,7 @@ static int ssd0323_init(SSISlave *dev)
s->col_end = 63;
s->row_end = 79;
- s->con = graphic_console_init(DEVICE(dev), &ssd0323_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, &ssd0323_ops, s);
qemu_console_resize(s->con, 128 * MAGNIFY, 64 * MAGNIFY);
qdev_init_gpio_in(&dev->qdev, ssd0323_cd, 1);
diff --git a/hw/display/tc6393xb.c b/hw/display/tc6393xb.c
index 3dd9b98eca..f4011d2db0 100644
--- a/hw/display/tc6393xb.c
+++ b/hw/display/tc6393xb.c
@@ -587,7 +587,7 @@ TC6393xbState *tc6393xb_init(MemoryRegion *sysmem, uint32_t base, qemu_irq irq)
memory_region_add_subregion(sysmem, base + 0x100000, &s->vram);
s->scr_width = 480;
s->scr_height = 640;
- s->con = graphic_console_init(NULL, &tc6393xb_gfx_ops, s);
+ s->con = graphic_console_init(NULL, 0, &tc6393xb_gfx_ops, s);
return s;
}
diff --git a/hw/display/tcx.c b/hw/display/tcx.c
index e60769c2c9..2b37ffac4c 100644
--- a/hw/display/tcx.c
+++ b/hw/display/tcx.c
@@ -602,14 +602,14 @@ static int tcx_init1(SysBusDevice *dev)
&s->vram_mem, vram_offset, size);
sysbus_init_mmio(dev, &s->vram_cplane);
- s->con = graphic_console_init(DEVICE(dev), &tcx24_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, &tcx24_ops, s);
} else {
/* THC 8 bit (dummy) */
memory_region_init_io(&s->thc8, OBJECT(s), &dummy_ops, s, "tcx.thc8",
TCX_THC_NREGS_8);
sysbus_init_mmio(dev, &s->thc8);
- s->con = graphic_console_init(DEVICE(dev), &tcx_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, &tcx_ops, s);
}
qemu_console_resize(s->con, s->width, s->height);
diff --git a/hw/display/vga-isa-mm.c b/hw/display/vga-isa-mm.c
index 8b514cc39d..afc46b8c9d 100644
--- a/hw/display/vga-isa-mm.c
+++ b/hw/display/vga-isa-mm.c
@@ -135,7 +135,7 @@ int isa_vga_mm_init(hwaddr vram_base,
vga_common_init(&s->vga, NULL);
vga_mm_init(s, vram_base, ctrl_base, it_shift, address_space);
- s->vga.con = graphic_console_init(NULL, s->vga.hw_ops, s);
+ s->vga.con = graphic_console_init(NULL, 0, s->vga.hw_ops, s);
vga_init_vbe(&s->vga, NULL, address_space);
return 0;
diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c
index c2a19ad6ba..1d9ea6b51d 100644
--- a/hw/display/vga-isa.c
+++ b/hw/display/vga-isa.c
@@ -67,7 +67,7 @@ static void vga_isa_realizefn(DeviceState *dev, Error **errp)
isa_mem_base + 0x000a0000,
vga_io_memory, 1);
memory_region_set_coalescing(vga_io_memory);
- s->con = graphic_console_init(DEVICE(dev), s->hw_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
vga_init_vbe(s, OBJECT(dev), isa_address_space(isadev));
/* ROM BIOS */
diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c
index f74fc43aa6..574ea0e7f9 100644
--- a/hw/display/vga-pci.c
+++ b/hw/display/vga-pci.c
@@ -151,7 +151,7 @@ static int pci_std_vga_initfn(PCIDevice *dev)
vga_init(s, OBJECT(dev), pci_address_space(dev), pci_address_space_io(dev),
true);
- s->con = graphic_console_init(DEVICE(dev), s->hw_ops, s);
+ s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
/* XXX: VGA_RAM_SIZE must be a power of two */
pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
index 334e71856e..bd2c108c42 100644
--- a/hw/display/vmware_vga.c
+++ b/hw/display/vmware_vga.c
@@ -1199,7 +1199,7 @@ static void vmsvga_init(DeviceState *dev, struct vmsvga_state_s *s,
s->scratch_size = SVGA_SCRATCH_SIZE;
s->scratch = g_malloc(s->scratch_size * 4);
- s->vga.con = graphic_console_init(dev, &vmsvga_ops, s);
+ s->vga.con = graphic_console_init(dev, 0, &vmsvga_ops, s);
s->fifo_size = SVGA_FIFO_SIZE;
memory_region_init_ram(&s->fifo_ram, NULL, "vmsvga.fifo", s->fifo_size);
diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c
index cb9d456814..032eb7a9a5 100644
--- a/hw/display/xenfb.c
+++ b/hw/display/xenfb.c
@@ -992,7 +992,7 @@ wait_more:
/* vfb */
fb = container_of(xfb, struct XenFB, c.xendev);
- fb->c.con = graphic_console_init(NULL, &xenfb_ops, fb);
+ fb->c.con = graphic_console_init(NULL, 0, &xenfb_ops, fb);
fb->have_console = 1;
/* vkbd */
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index d5dc1ef336..ae1699d6db 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -221,10 +221,16 @@ static void pc_init1(QEMUMachineInitArgs *args,
} else {
for(i = 0; i < MAX_IDE_BUS; i++) {
ISADevice *dev;
+ char busname[] = "ide.0";
dev = isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i],
ide_irq[i],
hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
- idebus[i] = qdev_get_child_bus(DEVICE(dev), "ide.0");
+ /*
+ * The ide bus name is ide.0 for the first bus and ide.1 for the
+ * second one.
+ */
+ busname[4] = '0' + i;
+ idebus[i] = qdev_get_child_bus(DEVICE(dev), busname);
}
}
diff --git a/hw/intc/openpic_kvm.c b/hw/intc/openpic_kvm.c
index c7f7b8406c..87fdb126cf 100644
--- a/hw/intc/openpic_kvm.c
+++ b/hw/intc/openpic_kvm.c
@@ -228,7 +228,7 @@ int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs)
encap.cap = KVM_CAP_IRQ_MPIC;
encap.args[0] = opp->fd;
- encap.args[1] = cs->cpu_index;
+ encap.args[1] = kvm_arch_vcpu_id(cs);
return kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap);
}
diff --git a/hw/intc/xics.c b/hw/intc/xics.c
index b437563fb9..64aabe753d 100644
--- a/hw/intc/xics.c
+++ b/hw/intc/xics.c
@@ -33,6 +33,17 @@
#include "qemu/error-report.h"
#include "qapi/visitor.h"
+static int get_cpu_index_by_dt_id(int cpu_dt_id)
+{
+ PowerPCCPU *cpu = ppc_get_vcpu_by_dt_id(cpu_dt_id);
+
+ if (cpu) {
+ return cpu->parent_obj.cpu_index;
+ }
+
+ return -1;
+}
+
void xics_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
{
CPUState *cs = CPU(cpu);
@@ -659,7 +670,7 @@ static target_ulong h_cppr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
static target_ulong h_ipi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args)
{
- target_ulong server = args[0];
+ target_ulong server = get_cpu_index_by_dt_id(args[0]);
target_ulong mfrr = args[1];
if (server >= spapr->icp->nr_servers) {
@@ -728,7 +739,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, sPAPREnvironment *spapr,
}
nr = rtas_ld(args, 0);
- server = rtas_ld(args, 1);
+ server = get_cpu_index_by_dt_id(rtas_ld(args, 1));
priority = rtas_ld(args, 2);
if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c
index c203646bd6..a5bbc2406d 100644
--- a/hw/intc/xics_kvm.c
+++ b/hw/intc/xics_kvm.c
@@ -65,7 +65,7 @@ static void icp_get_kvm_state(ICPState *ss)
ret = kvm_vcpu_ioctl(ss->cs, KVM_GET_ONE_REG, &reg);
if (ret != 0) {
error_report("Unable to retrieve KVM interrupt controller state"
- " for CPU %d: %s", ss->cs->cpu_index, strerror(errno));
+ " for CPU %ld: %s", kvm_arch_vcpu_id(ss->cs), strerror(errno));
exit(1);
}
@@ -97,7 +97,7 @@ static int icp_set_kvm_state(ICPState *ss, int version_id)
ret = kvm_vcpu_ioctl(ss->cs, KVM_SET_ONE_REG, &reg);
if (ret != 0) {
error_report("Unable to restore KVM interrupt controller state (0x%"
- PRIx64 ") for CPU %d: %s", state, ss->cs->cpu_index,
+ PRIx64 ") for CPU %ld: %s", state, kvm_arch_vcpu_id(ss->cs),
strerror(errno));
return ret;
}
@@ -325,15 +325,15 @@ static void xics_kvm_cpu_setup(XICSState *icp, PowerPCCPU *cpu)
struct kvm_enable_cap xics_enable_cap = {
.cap = KVM_CAP_IRQ_XICS,
.flags = 0,
- .args = {icpkvm->kernel_xics_fd, cs->cpu_index, 0, 0},
+ .args = {icpkvm->kernel_xics_fd, kvm_arch_vcpu_id(cs), 0, 0},
};
ss->cs = cs;
ret = kvm_vcpu_ioctl(ss->cs, KVM_ENABLE_CAP, &xics_enable_cap);
if (ret < 0) {
- error_report("Unable to connect CPU%d to kernel XICS: %s",
- cs->cpu_index, strerror(errno));
+ error_report("Unable to connect CPU%ld to kernel XICS: %s",
+ kvm_arch_vcpu_id(cs), strerror(errno));
exit(1);
}
}
diff --git a/hw/moxie/moxiesim.c b/hw/moxie/moxiesim.c
index ef4f3a84d7..a87ca6ddcc 100644
--- a/hw/moxie/moxiesim.c
+++ b/hw/moxie/moxiesim.c
@@ -55,7 +55,7 @@ static void load_kernel(MoxieCPU *cpu, LoaderParams *loader_params)
&entry, &kernel_low, &kernel_high, 1,
ELF_MACHINE, 0);
- if (!kernel_size) {
+ if (kernel_size <= 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
loader_params->kernel_filename);
exit(1);
diff --git a/hw/net/Makefile.objs b/hw/net/Makefile.objs
index 75e80c2c48..ea93293122 100644
--- a/hw/net/Makefile.objs
+++ b/hw/net/Makefile.objs
@@ -32,3 +32,6 @@ obj-$(CONFIG_XILINX_ETHLITE) += xilinx_ethlite.o
obj-$(CONFIG_VIRTIO) += virtio-net.o
obj-y += vhost_net.o
+
+obj-$(CONFIG_ETSEC) += fsl_etsec/etsec.o fsl_etsec/registers.o \
+ fsl_etsec/rings.o fsl_etsec/miim.o
diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c
new file mode 100644
index 0000000000..d4b4429446
--- /dev/null
+++ b/hw/net/fsl_etsec/etsec.c
@@ -0,0 +1,465 @@
+/*
+ * QEMU Freescale eTSEC Emulator
+ *
+ * Copyright (c) 2011-2013 AdaCore
+ *
+ * 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.
+ */
+
+/*
+ * This implementation doesn't include ring priority, TCP/IP Off-Load, QoS.
+ */
+
+#include "sysemu/sysemu.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "hw/ptimer.h"
+#include "etsec.h"
+#include "registers.h"
+
+/* #define HEX_DUMP */
+/* #define DEBUG_REGISTER */
+
+#ifdef DEBUG_REGISTER
+static const int debug_etsec = 1;
+#else
+static const int debug_etsec;
+#endif
+
+#define DPRINTF(fmt, ...) do { \
+ if (debug_etsec) { \
+ qemu_log(fmt , ## __VA_ARGS__); \
+ } \
+ } while (0)
+
+static uint64_t etsec_read(void *opaque, hwaddr addr, unsigned size)
+{
+ eTSEC *etsec = opaque;
+ uint32_t reg_index = addr / 4;
+ eTSEC_Register *reg = NULL;
+ uint32_t ret = 0x0;
+
+ assert(reg_index < ETSEC_REG_NUMBER);
+
+ reg = &etsec->regs[reg_index];
+
+
+ switch (reg->access) {
+ case ACC_WO:
+ ret = 0x00000000;
+ break;
+
+ case ACC_RW:
+ case ACC_W1C:
+ case ACC_RO:
+ default:
+ ret = reg->value;
+ break;
+ }
+
+ DPRINTF("Read 0x%08x @ 0x" TARGET_FMT_plx
+ " : %s (%s)\n",
+ ret, addr, reg->name, reg->desc);
+
+ return ret;
+}
+
+static void write_tstat(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value)
+{
+ int i = 0;
+
+ for (i = 0; i < 8; i++) {
+ /* Check THLTi flag in TSTAT */
+ if (value & (1 << (31 - i))) {
+ etsec_walk_tx_ring(etsec, i);
+ }
+ }
+
+ /* Write 1 to clear */
+ reg->value &= ~value;
+}
+
+static void write_rstat(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value)
+{
+ int i = 0;
+
+ for (i = 0; i < 8; i++) {
+ /* Check QHLTi flag in RSTAT */
+ if (value & (1 << (23 - i)) && !(reg->value & (1 << (23 - i)))) {
+ etsec_walk_rx_ring(etsec, i);
+ }
+ }
+
+ /* Write 1 to clear */
+ reg->value &= ~value;
+}
+
+static void write_tbasex(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value)
+{
+ reg->value = value & ~0x7;
+
+ /* Copy this value in the ring's TxBD pointer */
+ etsec->regs[TBPTR0 + (reg_index - TBASE0)].value = value & ~0x7;
+}
+
+static void write_rbasex(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value)
+{
+ reg->value = value & ~0x7;
+
+ /* Copy this value in the ring's RxBD pointer */
+ etsec->regs[RBPTR0 + (reg_index - RBASE0)].value = value & ~0x7;
+}
+
+static void write_ievent(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value)
+{
+ /* Write 1 to clear */
+ reg->value &= ~value;
+
+ if (!(reg->value & (IEVENT_TXF | IEVENT_TXF))) {
+ qemu_irq_lower(etsec->tx_irq);
+ }
+ if (!(reg->value & (IEVENT_RXF | IEVENT_RXF))) {
+ qemu_irq_lower(etsec->rx_irq);
+ }
+
+ if (!(reg->value & (IEVENT_MAG | IEVENT_GTSC | IEVENT_GRSC | IEVENT_TXC |
+ IEVENT_RXC | IEVENT_BABR | IEVENT_BABT | IEVENT_LC |
+ IEVENT_CRL | IEVENT_FGPI | IEVENT_FIR | IEVENT_FIQ |
+ IEVENT_DPE | IEVENT_PERR | IEVENT_EBERR | IEVENT_TXE |
+ IEVENT_XFUN | IEVENT_BSY | IEVENT_MSRO | IEVENT_MMRD |
+ IEVENT_MMRW))) {
+ qemu_irq_lower(etsec->err_irq);
+ }
+}
+
+static void write_dmactrl(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value)
+{
+ reg->value = value;
+
+ if (value & DMACTRL_GRS) {
+
+ if (etsec->rx_buffer_len != 0) {
+ /* Graceful receive stop delayed until end of frame */
+ } else {
+ /* Graceful receive stop now */
+ etsec->regs[IEVENT].value |= IEVENT_GRSC;
+ if (etsec->regs[IMASK].value & IMASK_GRSCEN) {
+ qemu_irq_raise(etsec->err_irq);
+ }
+ }
+ }
+
+ if (value & DMACTRL_GTS) {
+
+ if (etsec->tx_buffer_len != 0) {
+ /* Graceful transmit stop delayed until end of frame */
+ } else {
+ /* Graceful transmit stop now */
+ etsec->regs[IEVENT].value |= IEVENT_GTSC;
+ if (etsec->regs[IMASK].value & IMASK_GTSCEN) {
+ qemu_irq_raise(etsec->err_irq);
+ }
+ }
+ }
+
+ if (!(value & DMACTRL_WOP)) {
+ /* Start polling */
+ ptimer_stop(etsec->ptimer);
+ ptimer_set_count(etsec->ptimer, 1);
+ ptimer_run(etsec->ptimer, 1);
+ }
+}
+
+static void etsec_write(void *opaque,
+ hwaddr addr,
+ uint64_t value,
+ unsigned size)
+{
+ eTSEC *etsec = opaque;
+ uint32_t reg_index = addr / 4;
+ eTSEC_Register *reg = NULL;
+ uint32_t before = 0x0;
+
+ assert(reg_index < ETSEC_REG_NUMBER);
+
+ reg = &etsec->regs[reg_index];
+ before = reg->value;
+
+ switch (reg_index) {
+ case IEVENT:
+ write_ievent(etsec, reg, reg_index, value);
+ break;
+
+ case DMACTRL:
+ write_dmactrl(etsec, reg, reg_index, value);
+ break;
+
+ case TSTAT:
+ write_tstat(etsec, reg, reg_index, value);
+ break;
+
+ case RSTAT:
+ write_rstat(etsec, reg, reg_index, value);
+ break;
+
+ case TBASE0 ... TBASE7:
+ write_tbasex(etsec, reg, reg_index, value);
+ break;
+
+ case RBASE0 ... RBASE7:
+ write_rbasex(etsec, reg, reg_index, value);
+ break;
+
+ case MIIMCFG ... MIIMIND:
+ etsec_write_miim(etsec, reg, reg_index, value);
+ break;
+
+ default:
+ /* Default handling */
+ switch (reg->access) {
+
+ case ACC_RW:
+ case ACC_WO:
+ reg->value = value;
+ break;
+
+ case ACC_W1C:
+ reg->value &= ~value;
+ break;
+
+ case ACC_RO:
+ default:
+ /* Read Only or Unknown register */
+ break;
+ }
+ }
+
+ DPRINTF("Write 0x%08x @ 0x" TARGET_FMT_plx
+ " val:0x%08x->0x%08x : %s (%s)\n",
+ (unsigned int)value, addr, before, reg->value,
+ reg->name, reg->desc);
+}
+
+static const MemoryRegionOps etsec_ops = {
+ .read = etsec_read,
+ .write = etsec_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static void etsec_timer_hit(void *opaque)
+{
+ eTSEC *etsec = opaque;
+
+ ptimer_stop(etsec->ptimer);
+
+ if (!(etsec->regs[DMACTRL].value & DMACTRL_WOP)) {
+
+ if (!(etsec->regs[DMACTRL].value & DMACTRL_GTS)) {
+ etsec_walk_tx_ring(etsec, 0);
+ }
+ ptimer_set_count(etsec->ptimer, 1);
+ ptimer_run(etsec->ptimer, 1);
+ }
+}
+
+static void etsec_reset(DeviceState *d)
+{
+ eTSEC *etsec = ETSEC_COMMON(d);
+ int i = 0;
+ int reg_index = 0;
+
+ /* Default value for all registers */
+ for (i = 0; i < ETSEC_REG_NUMBER; i++) {
+ etsec->regs[i].name = "Reserved";
+ etsec->regs[i].desc = "";
+ etsec->regs[i].access = ACC_UNKNOWN;
+ etsec->regs[i].value = 0x00000000;
+ }
+
+ /* Set-up known registers */
+ for (i = 0; eTSEC_registers_def[i].name != NULL; i++) {
+
+ reg_index = eTSEC_registers_def[i].offset / 4;
+
+ etsec->regs[reg_index].name = eTSEC_registers_def[i].name;
+ etsec->regs[reg_index].desc = eTSEC_registers_def[i].desc;
+ etsec->regs[reg_index].access = eTSEC_registers_def[i].access;
+ etsec->regs[reg_index].value = eTSEC_registers_def[i].reset;
+ }
+
+ etsec->tx_buffer = NULL;
+ etsec->tx_buffer_len = 0;
+ etsec->rx_buffer = NULL;
+ etsec->rx_buffer_len = 0;
+
+ etsec->phy_status =
+ MII_SR_EXTENDED_CAPS | MII_SR_LINK_STATUS | MII_SR_AUTONEG_CAPS |
+ MII_SR_AUTONEG_COMPLETE | MII_SR_PREAMBLE_SUPPRESS |
+ MII_SR_EXTENDED_STATUS | MII_SR_100T2_HD_CAPS | MII_SR_100T2_FD_CAPS |
+ MII_SR_10T_HD_CAPS | MII_SR_10T_FD_CAPS | MII_SR_100X_HD_CAPS |
+ MII_SR_100X_FD_CAPS | MII_SR_100T4_CAPS;
+}
+
+static void etsec_cleanup(NetClientState *nc)
+{
+ /* qemu_log("eTSEC cleanup\n"); */
+}
+
+static int etsec_can_receive(NetClientState *nc)
+{
+ eTSEC *etsec = qemu_get_nic_opaque(nc);
+
+ return etsec->rx_buffer_len == 0;
+}
+
+static ssize_t etsec_receive(NetClientState *nc,
+ const uint8_t *buf,
+ size_t size)
+{
+ eTSEC *etsec = qemu_get_nic_opaque(nc);
+
+#if defined(HEX_DUMP)
+ fprintf(stderr, "%s receive size:%d\n", etsec->nic->nc.name, size);
+ qemu_hexdump(buf, stderr, "", size);
+#endif
+ etsec_rx_ring_write(etsec, buf, size);
+ return size;
+}
+
+
+static void etsec_set_link_status(NetClientState *nc)
+{
+ eTSEC *etsec = qemu_get_nic_opaque(nc);
+
+ etsec_miim_link_status(etsec, nc);
+}
+
+static NetClientInfo net_etsec_info = {
+ .type = NET_CLIENT_OPTIONS_KIND_NIC,
+ .size = sizeof(NICState),
+ .can_receive = etsec_can_receive,
+ .receive = etsec_receive,
+ .cleanup = etsec_cleanup,
+ .link_status_changed = etsec_set_link_status,
+};
+
+static void etsec_realize(DeviceState *dev, Error **errp)
+{
+ eTSEC *etsec = ETSEC_COMMON(dev);
+
+ etsec->nic = qemu_new_nic(&net_etsec_info, &etsec->conf,
+ object_get_typename(OBJECT(dev)), dev->id, etsec);
+ qemu_format_nic_info_str(qemu_get_queue(etsec->nic), etsec->conf.macaddr.a);
+
+
+ etsec->bh = qemu_bh_new(etsec_timer_hit, etsec);
+ etsec->ptimer = ptimer_init(etsec->bh);
+ ptimer_set_freq(etsec->ptimer, 100);
+}
+
+static void etsec_instance_init(Object *obj)
+{
+ eTSEC *etsec = ETSEC_COMMON(obj);
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+
+ memory_region_init_io(&etsec->io_area, OBJECT(etsec), &etsec_ops, etsec,
+ "eTSEC", 0x1000);
+ sysbus_init_mmio(sbd, &etsec->io_area);
+
+ sysbus_init_irq(sbd, &etsec->tx_irq);
+ sysbus_init_irq(sbd, &etsec->rx_irq);
+ sysbus_init_irq(sbd, &etsec->err_irq);
+}
+
+static Property etsec_properties[] = {
+ DEFINE_NIC_PROPERTIES(eTSEC, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void etsec_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = etsec_realize;
+ dc->reset = etsec_reset;
+ dc->props = etsec_properties;
+}
+
+static TypeInfo etsec_info = {
+ .name = "eTSEC",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(eTSEC),
+ .class_init = etsec_class_init,
+ .instance_init = etsec_instance_init,
+};
+
+static void etsec_register_types(void)
+{
+ type_register_static(&etsec_info);
+}
+
+type_init(etsec_register_types)
+
+DeviceState *etsec_create(hwaddr base,
+ MemoryRegion * mr,
+ NICInfo * nd,
+ qemu_irq tx_irq,
+ qemu_irq rx_irq,
+ qemu_irq err_irq)
+{
+ DeviceState *dev;
+
+ dev = qdev_create(NULL, "eTSEC");
+ qdev_set_nic_properties(dev, nd);
+
+ if (qdev_init(dev)) {
+ return NULL;
+ }
+
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, tx_irq);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 1, rx_irq);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 2, err_irq);
+
+ memory_region_add_subregion(mr, base,
+ SYS_BUS_DEVICE(dev)->mmio[0].memory);
+
+ return dev;
+}
diff --git a/hw/net/fsl_etsec/etsec.h b/hw/net/fsl_etsec/etsec.h
new file mode 100644
index 0000000000..78d2c57ed3
--- /dev/null
+++ b/hw/net/fsl_etsec/etsec.h
@@ -0,0 +1,174 @@
+/*
+ * QEMU Freescale eTSEC Emulator
+ *
+ * Copyright (c) 2011-2013 AdaCore
+ *
+ * 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.
+ */
+#ifndef _ETSEC_H_
+#define _ETSEC_H_
+
+#include "hw/qdev.h"
+#include "hw/sysbus.h"
+#include "net/net.h"
+#include "hw/ptimer.h"
+
+/* Buffer Descriptors */
+
+typedef struct eTSEC_rxtx_bd {
+ uint16_t flags;
+ uint16_t length;
+ uint32_t bufptr;
+} eTSEC_rxtx_bd;
+
+#define BD_WRAP (1 << 13)
+#define BD_INTERRUPT (1 << 12)
+#define BD_LAST (1 << 11)
+
+#define BD_TX_READY (1 << 15)
+#define BD_TX_PADCRC (1 << 14)
+#define BD_TX_TC (1 << 10)
+#define BD_TX_PREDEF (1 << 9)
+#define BD_TX_HFELC (1 << 7)
+#define BD_TX_CFRL (1 << 6)
+#define BD_TX_RC_MASK 0xF
+#define BD_TX_RC_OFFSET 0x2
+#define BD_TX_TOEUN (1 << 1)
+#define BD_TX_TR (1 << 0)
+
+#define BD_RX_EMPTY (1 << 15)
+#define BD_RX_RO1 (1 << 14)
+#define BD_RX_FIRST (1 << 10)
+#define BD_RX_MISS (1 << 8)
+#define BD_RX_BROADCAST (1 << 7)
+#define BD_RX_MULTICAST (1 << 6)
+#define BD_RX_LG (1 << 5)
+#define BD_RX_NO (1 << 4)
+#define BD_RX_SH (1 << 3)
+#define BD_RX_CR (1 << 2)
+#define BD_RX_OV (1 << 1)
+#define BD_RX_TR (1 << 0)
+
+/* Tx FCB flags */
+#define FCB_TX_VLN (1 << 7)
+#define FCB_TX_IP (1 << 6)
+#define FCB_TX_IP6 (1 << 5)
+#define FCB_TX_TUP (1 << 4)
+#define FCB_TX_UDP (1 << 3)
+#define FCB_TX_CIP (1 << 2)
+#define FCB_TX_CTU (1 << 1)
+#define FCB_TX_NPH (1 << 0)
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS 0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT 0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS 0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS 0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT 0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE 0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS 0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS 0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS 0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS 0x0800 /* 10T Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS 0x1000 /* 10T Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS 0x2000 /* 100X Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS 0x4000 /* 100X Full Duplex Capable */
+#define MII_SR_100T4_CAPS 0x8000 /* 100T4 Capable */
+
+/* eTSEC */
+
+/* Number of register in the device */
+#define ETSEC_REG_NUMBER 1024
+
+typedef struct eTSEC_Register {
+ const char *name;
+ const char *desc;
+ uint32_t access;
+ uint32_t value;
+} eTSEC_Register;
+
+typedef struct eTSEC {
+ SysBusDevice busdev;
+
+ MemoryRegion io_area;
+
+ eTSEC_Register regs[ETSEC_REG_NUMBER];
+
+ NICState *nic;
+ NICConf conf;
+
+ /* Tx */
+
+ uint8_t *tx_buffer;
+ uint32_t tx_buffer_len;
+ eTSEC_rxtx_bd first_bd;
+
+ /* Rx */
+
+ uint8_t *rx_buffer;
+ uint32_t rx_buffer_len;
+ uint32_t rx_remaining_data;
+ uint8_t rx_first_in_frame;
+ uint8_t rx_fcb_size;
+ eTSEC_rxtx_bd rx_first_bd;
+ uint8_t rx_fcb[10];
+ uint32_t rx_padding;
+
+ /* IRQs */
+ qemu_irq tx_irq;
+ qemu_irq rx_irq;
+ qemu_irq err_irq;
+
+
+ uint16_t phy_status;
+ uint16_t phy_control;
+
+ /* Polling */
+ QEMUBH *bh;
+ struct ptimer_state *ptimer;
+
+} eTSEC;
+
+#define TYPE_ETSEC_COMMON "eTSEC"
+#define ETSEC_COMMON(obj) \
+ OBJECT_CHECK(eTSEC, (obj), TYPE_ETSEC_COMMON)
+
+#define eTSEC_TRANSMIT 1
+#define eTSEC_RECEIVE 2
+
+DeviceState *etsec_create(hwaddr base,
+ MemoryRegion *mr,
+ NICInfo *nd,
+ qemu_irq tx_irq,
+ qemu_irq rx_irq,
+ qemu_irq err_irq);
+
+void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr);
+void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr);
+void etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size);
+
+void etsec_write_miim(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value);
+
+void etsec_miim_link_status(eTSEC *etsec, NetClientState *nc);
+
+#endif /* ! _ETSEC_H_ */
diff --git a/hw/net/fsl_etsec/miim.c b/hw/net/fsl_etsec/miim.c
new file mode 100644
index 0000000000..1931b74e6c
--- /dev/null
+++ b/hw/net/fsl_etsec/miim.c
@@ -0,0 +1,146 @@
+/*
+ * QEMU Freescale eTSEC Emulator
+ *
+ * Copyright (c) 2011-2013 AdaCore
+ *
+ * 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.
+ */
+
+#include "etsec.h"
+#include "registers.h"
+
+/* #define DEBUG_MIIM */
+
+#define MIIM_CONTROL 0
+#define MIIM_STATUS 1
+#define MIIM_PHY_ID_1 2
+#define MIIM_PHY_ID_2 3
+#define MIIM_T2_STATUS 10
+#define MIIM_EXT_STATUS 15
+
+static void miim_read_cycle(eTSEC *etsec)
+{
+ uint8_t phy;
+ uint8_t addr;
+ uint16_t value;
+
+ phy = (etsec->regs[MIIMADD].value >> 8) & 0x1F;
+ (void)phy; /* Unreferenced */
+ addr = etsec->regs[MIIMADD].value & 0x1F;
+
+ switch (addr) {
+ case MIIM_CONTROL:
+ value = etsec->phy_control;
+ break;
+ case MIIM_STATUS:
+ value = etsec->phy_status;
+ break;
+ case MIIM_T2_STATUS:
+ value = 0x1800; /* Local and remote receivers OK */
+ break;
+ default:
+ value = 0x0;
+ break;
+ };
+
+#ifdef DEBUG_MIIM
+ qemu_log("%s phy:%d addr:0x%x value:0x%x\n", __func__, phy, addr, value);
+#endif
+
+ etsec->regs[MIIMSTAT].value = value;
+}
+
+static void miim_write_cycle(eTSEC *etsec)
+{
+ uint8_t phy;
+ uint8_t addr;
+ uint16_t value;
+
+ phy = (etsec->regs[MIIMADD].value >> 8) & 0x1F;
+ (void)phy; /* Unreferenced */
+ addr = etsec->regs[MIIMADD].value & 0x1F;
+ value = etsec->regs[MIIMCON].value & 0xffff;
+
+#ifdef DEBUG_MIIM
+ qemu_log("%s phy:%d addr:0x%x value:0x%x\n", __func__, phy, addr, value);
+#endif
+
+ switch (addr) {
+ case MIIM_CONTROL:
+ etsec->phy_control = value & ~(0x8100);
+ break;
+ default:
+ break;
+ };
+}
+
+void etsec_write_miim(eTSEC *etsec,
+ eTSEC_Register *reg,
+ uint32_t reg_index,
+ uint32_t value)
+{
+
+ switch (reg_index) {
+
+ case MIIMCOM:
+ /* Read and scan cycle */
+
+ if ((!(reg->value & MIIMCOM_READ)) && (value & MIIMCOM_READ)) {
+ /* Read */
+ miim_read_cycle(etsec);
+ }
+ reg->value = value;
+ break;
+
+ case MIIMCON:
+ reg->value = value & 0xffff;
+ miim_write_cycle(etsec);
+ break;
+
+ default:
+ /* Default handling */
+ switch (reg->access) {
+
+ case ACC_RW:
+ case ACC_WO:
+ reg->value = value;
+ break;
+
+ case ACC_W1C:
+ reg->value &= ~value;
+ break;
+
+ case ACC_RO:
+ default:
+ /* Read Only or Unknown register */
+ break;
+ }
+ }
+
+}
+
+void etsec_miim_link_status(eTSEC *etsec, NetClientState *nc)
+{
+ /* Set link status */
+ if (nc->link_down) {
+ etsec->phy_status &= ~MII_SR_LINK_STATUS;
+ } else {
+ etsec->phy_status |= MII_SR_LINK_STATUS;
+ }
+}
diff --git a/hw/net/fsl_etsec/registers.c b/hw/net/fsl_etsec/registers.c
new file mode 100644
index 0000000000..a7bbfa113f
--- /dev/null
+++ b/hw/net/fsl_etsec/registers.c
@@ -0,0 +1,295 @@
+/*
+ * QEMU Freescale eTSEC Emulator
+ *
+ * Copyright (c) 2011-2013 AdaCore
+ *
+ * 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.
+ */
+#include "registers.h"
+
+const eTSEC_Register_Definition eTSEC_registers_def[] = {
+{0x000, "TSEC_ID", "Controller ID register", ACC_RO, 0x01240000},
+{0x004, "TSEC_ID2", "Controller ID register 2", ACC_RO, 0x003000F0},
+{0x010, "IEVENT", "Interrupt event register", ACC_W1C, 0x00000000},
+{0x014, "IMASK", "Interrupt mask register", ACC_RW, 0x00000000},
+{0x018, "EDIS", "Error disabled register", ACC_RW, 0x00000000},
+{0x020, "ECNTRL", "Ethernet control register", ACC_RW, 0x00000040},
+{0x028, "PTV", "Pause time value register", ACC_RW, 0x00000000},
+{0x02C, "DMACTRL", "DMA control register", ACC_RW, 0x00000000},
+{0x030, "TBIPA", "TBI PHY address register", ACC_RW, 0x00000000},
+
+/* eTSEC FIFO Control and Status Registers */
+
+{0x058, "FIFO_RX_ALARM", "FIFO receive alarm start threshold register", ACC_RW, 0x00000040},
+{0x05C, "FIFO_RX_ALARM_SHUTOFF", "FIFO receive alarm shut-off threshold register", ACC_RW, 0x00000080},
+{0x08C, "FIFO_TX_THR", "FIFO transmit threshold register", ACC_RW, 0x00000080},
+{0x098, "FIFO_TX_STARVE", "FIFO transmit starve register", ACC_RW, 0x00000040},
+{0x09C, "FIFO_TX_STARVE_SHUTOFF", "FIFO transmit starve shut-off register", ACC_RW, 0x00000080},
+
+/* eTSEC Transmit Control and Status Registers */
+
+{0x100, "TCTRL", "Transmit control register", ACC_RW, 0x00000000},
+{0x104, "TSTAT", "Transmit status register", ACC_W1C, 0x00000000},
+{0x108, "DFVLAN", "Default VLAN control word", ACC_RW, 0x81000000},
+{0x110, "TXIC", "Transmit interrupt coalescing register", ACC_RW, 0x00000000},
+{0x114, "TQUEUE", "Transmit queue control register", ACC_RW, 0x00008000},
+{0x140, "TR03WT", "TxBD Rings 0-3 round-robin weightings", ACC_RW, 0x00000000},
+{0x144, "TR47WT", "TxBD Rings 4-7 round-robin weightings", ACC_RW, 0x00000000},
+{0x180, "TBDBPH", "Tx data buffer pointer high bits", ACC_RW, 0x00000000},
+{0x184, "TBPTR0", "TxBD pointer for ring 0", ACC_RW, 0x00000000},
+{0x18C, "TBPTR1", "TxBD pointer for ring 1", ACC_RW, 0x00000000},
+{0x194, "TBPTR2", "TxBD pointer for ring 2", ACC_RW, 0x00000000},
+{0x19C, "TBPTR3", "TxBD pointer for ring 3", ACC_RW, 0x00000000},
+{0x1A4, "TBPTR4", "TxBD pointer for ring 4", ACC_RW, 0x00000000},
+{0x1AC, "TBPTR5", "TxBD pointer for ring 5", ACC_RW, 0x00000000},
+{0x1B4, "TBPTR6", "TxBD pointer for ring 6", ACC_RW, 0x00000000},
+{0x1BC, "TBPTR7", "TxBD pointer for ring 7", ACC_RW, 0x00000000},
+{0x200, "TBASEH", "TxBD base address high bits", ACC_RW, 0x00000000},
+{0x204, "TBASE0", "TxBD base address of ring 0", ACC_RW, 0x00000000},
+{0x20C, "TBASE1", "TxBD base address of ring 1", ACC_RW, 0x00000000},
+{0x214, "TBASE2", "TxBD base address of ring 2", ACC_RW, 0x00000000},
+{0x21C, "TBASE3", "TxBD base address of ring 3", ACC_RW, 0x00000000},
+{0x224, "TBASE4", "TxBD base address of ring 4", ACC_RW, 0x00000000},
+{0x22C, "TBASE5", "TxBD base address of ring 5", ACC_RW, 0x00000000},
+{0x234, "TBASE6", "TxBD base address of ring 6", ACC_RW, 0x00000000},
+{0x23C, "TBASE7", "TxBD base address of ring 7", ACC_RW, 0x00000000},
+{0x280, "TMR_TXTS1_ID", "Tx time stamp identification tag (set 1)", ACC_RO, 0x00000000},
+{0x284, "TMR_TXTS2_ID", "Tx time stamp identification tag (set 2)", ACC_RO, 0x00000000},
+{0x2C0, "TMR_TXTS1_H", "Tx time stamp high (set 1)", ACC_RO, 0x00000000},
+{0x2C4, "TMR_TXTS1_L", "Tx time stamp high (set 1)", ACC_RO, 0x00000000},
+{0x2C8, "TMR_TXTS2_H", "Tx time stamp high (set 2)", ACC_RO, 0x00000000},
+{0x2CC, "TMR_TXTS2_L", "Tx time stamp high (set 2)", ACC_RO, 0x00000000},
+
+/* eTSEC Receive Control and Status Registers */
+
+{0x300, "RCTRL", "Receive control register", ACC_RW, 0x00000000},
+{0x304, "RSTAT", "Receive status register", ACC_W1C, 0x00000000},
+{0x310, "RXIC", "Receive interrupt coalescing register", ACC_RW, 0x00000000},
+{0x314, "RQUEUE", "Receive queue control register.", ACC_RW, 0x00800080},
+{0x330, "RBIFX", "Receive bit field extract control register", ACC_RW, 0x00000000},
+{0x334, "RQFAR", "Receive queue filing table address register", ACC_RW, 0x00000000},
+{0x338, "RQFCR", "Receive queue filing table control register", ACC_RW, 0x00000000},
+{0x33C, "RQFPR", "Receive queue filing table property register", ACC_RW, 0x00000000},
+{0x340, "MRBLR", "Maximum receive buffer length register", ACC_RW, 0x00000000},
+{0x380, "RBDBPH", "Rx data buffer pointer high bits", ACC_RW, 0x00000000},
+{0x384, "RBPTR0", "RxBD pointer for ring 0", ACC_RW, 0x00000000},
+{0x38C, "RBPTR1", "RxBD pointer for ring 1", ACC_RW, 0x00000000},
+{0x394, "RBPTR2", "RxBD pointer for ring 2", ACC_RW, 0x00000000},
+{0x39C, "RBPTR3", "RxBD pointer for ring 3", ACC_RW, 0x00000000},
+{0x3A4, "RBPTR4", "RxBD pointer for ring 4", ACC_RW, 0x00000000},
+{0x3AC, "RBPTR5", "RxBD pointer for ring 5", ACC_RW, 0x00000000},
+{0x3B4, "RBPTR6", "RxBD pointer for ring 6", ACC_RW, 0x00000000},
+{0x3BC, "RBPTR7", "RxBD pointer for ring 7", ACC_RW, 0x00000000},
+{0x400, "RBASEH", "RxBD base address high bits", ACC_RW, 0x00000000},
+{0x404, "RBASE0", "RxBD base address of ring 0", ACC_RW, 0x00000000},
+{0x40C, "RBASE1", "RxBD base address of ring 1", ACC_RW, 0x00000000},
+{0x414, "RBASE2", "RxBD base address of ring 2", ACC_RW, 0x00000000},
+{0x41C, "RBASE3", "RxBD base address of ring 3", ACC_RW, 0x00000000},
+{0x424, "RBASE4", "RxBD base address of ring 4", ACC_RW, 0x00000000},
+{0x42C, "RBASE5", "RxBD base address of ring 5", ACC_RW, 0x00000000},
+{0x434, "RBASE6", "RxBD base address of ring 6", ACC_RW, 0x00000000},
+{0x43C, "RBASE7", "RxBD base address of ring 7", ACC_RW, 0x00000000},
+{0x4C0, "TMR_RXTS_H", "Rx timer time stamp register high", ACC_RW, 0x00000000},
+{0x4C4, "TMR_RXTS_L", "Rx timer time stamp register low", ACC_RW, 0x00000000},
+
+/* eTSEC MAC Registers */
+
+{0x500, "MACCFG1", "MAC configuration register 1", ACC_RW, 0x00000000},
+{0x504, "MACCFG2", "MAC configuration register 2", ACC_RW, 0x00007000},
+{0x508, "IPGIFG", "Inter-packet/inter-frame gap register", ACC_RW, 0x40605060},
+{0x50C, "HAFDUP", "Half-duplex control", ACC_RW, 0x00A1F037},
+{0x510, "MAXFRM", "Maximum frame length", ACC_RW, 0x00000600},
+{0x520, "MIIMCFG", "MII management configuration", ACC_RW, 0x00000007},
+{0x524, "MIIMCOM", "MII management command", ACC_RW, 0x00000000},
+{0x528, "MIIMADD", "MII management address", ACC_RW, 0x00000000},
+{0x52C, "MIIMCON", "MII management control", ACC_WO, 0x00000000},
+{0x530, "MIIMSTAT", "MII management status", ACC_RO, 0x00000000},
+{0x534, "MIIMIND", "MII management indicator", ACC_RO, 0x00000000},
+{0x53C, "IFSTAT", "Interface status", ACC_RO, 0x00000000},
+{0x540, "MACSTNADDR1", "MAC station address register 1", ACC_RW, 0x00000000},
+{0x544, "MACSTNADDR2", "MAC station address register 2", ACC_RW, 0x00000000},
+{0x548, "MAC01ADDR1", "MAC exact match address 1, part 1", ACC_RW, 0x00000000},
+{0x54C, "MAC01ADDR2", "MAC exact match address 1, part 2", ACC_RW, 0x00000000},
+{0x550, "MAC02ADDR1", "MAC exact match address 2, part 1", ACC_RW, 0x00000000},
+{0x554, "MAC02ADDR2", "MAC exact match address 2, part 2", ACC_RW, 0x00000000},
+{0x558, "MAC03ADDR1", "MAC exact match address 3, part 1", ACC_RW, 0x00000000},
+{0x55C, "MAC03ADDR2", "MAC exact match address 3, part 2", ACC_RW, 0x00000000},
+{0x560, "MAC04ADDR1", "MAC exact match address 4, part 1", ACC_RW, 0x00000000},
+{0x564, "MAC04ADDR2", "MAC exact match address 4, part 2", ACC_RW, 0x00000000},
+{0x568, "MAC05ADDR1", "MAC exact match address 5, part 1", ACC_RW, 0x00000000},
+{0x56C, "MAC05ADDR2", "MAC exact match address 5, part 2", ACC_RW, 0x00000000},
+{0x570, "MAC06ADDR1", "MAC exact match address 6, part 1", ACC_RW, 0x00000000},
+{0x574, "MAC06ADDR2", "MAC exact match address 6, part 2", ACC_RW, 0x00000000},
+{0x578, "MAC07ADDR1", "MAC exact match address 7, part 1", ACC_RW, 0x00000000},
+{0x57C, "MAC07ADDR2", "MAC exact match address 7, part 2", ACC_RW, 0x00000000},
+{0x580, "MAC08ADDR1", "MAC exact match address 8, part 1", ACC_RW, 0x00000000},
+{0x584, "MAC08ADDR2", "MAC exact match address 8, part 2", ACC_RW, 0x00000000},
+{0x588, "MAC09ADDR1", "MAC exact match address 9, part 1", ACC_RW, 0x00000000},
+{0x58C, "MAC09ADDR2", "MAC exact match address 9, part 2", ACC_RW, 0x00000000},
+{0x590, "MAC10ADDR1", "MAC exact match address 10, part 1", ACC_RW, 0x00000000},
+{0x594, "MAC10ADDR2", "MAC exact match address 10, part 2", ACC_RW, 0x00000000},
+{0x598, "MAC11ADDR1", "MAC exact match address 11, part 1", ACC_RW, 0x00000000},
+{0x59C, "MAC11ADDR2", "MAC exact match address 11, part 2", ACC_RW, 0x00000000},
+{0x5A0, "MAC12ADDR1", "MAC exact match address 12, part 1", ACC_RW, 0x00000000},
+{0x5A4, "MAC12ADDR2", "MAC exact match address 12, part 2", ACC_RW, 0x00000000},
+{0x5A8, "MAC13ADDR1", "MAC exact match address 13, part 1", ACC_RW, 0x00000000},
+{0x5AC, "MAC13ADDR2", "MAC exact match address 13, part 2", ACC_RW, 0x00000000},
+{0x5B0, "MAC14ADDR1", "MAC exact match address 14, part 1", ACC_RW, 0x00000000},
+{0x5B4, "MAC14ADDR2", "MAC exact match address 14, part 2", ACC_RW, 0x00000000},
+{0x5B8, "MAC15ADDR1", "MAC exact match address 15, part 1", ACC_RW, 0x00000000},
+{0x5BC, "MAC15ADDR2", "MAC exact match address 15, part 2", ACC_RW, 0x00000000},
+
+/* eTSEC, "Transmit", "and", Receive, Counters */
+
+{0x680, "TR64", "Transmit and receive 64-byte frame counter ", ACC_RW, 0x00000000},
+{0x684, "TR127", "Transmit and receive 65- to 127-byte frame counter", ACC_RW, 0x00000000},
+{0x688, "TR255", "Transmit and receive 128- to 255-byte frame counter", ACC_RW, 0x00000000},
+{0x68C, "TR511", "Transmit and receive 256- to 511-byte frame counter", ACC_RW, 0x00000000},
+{0x690, "TR1K", "Transmit and receive 512- to 1023-byte frame counter", ACC_RW, 0x00000000},
+{0x694, "TRMAX", "Transmit and receive 1024- to 1518-byte frame counter", ACC_RW, 0x00000000},
+{0x698, "TRMGV", "Transmit and receive 1519- to 1522-byte good VLAN frame count", ACC_RW, 0x00000000},
+
+/* eTSEC Receive Counters */
+
+{0x69C, "RBYT", "Receive byte counter", ACC_RW, 0x00000000},
+{0x6A0, "RPKT", "Receive packet counter", ACC_RW, 0x00000000},
+{0x6A4, "RFCS", "Receive FCS error counter", ACC_RW, 0x00000000},
+{0x6A8, "RMCA", "Receive multicast packet counter", ACC_RW, 0x00000000},
+{0x6AC, "RBCA", "Receive broadcast packet counter", ACC_RW, 0x00000000},
+{0x6B0, "RXCF", "Receive control frame packet counter ", ACC_RW, 0x00000000},
+{0x6B4, "RXPF", "Receive PAUSE frame packet counter", ACC_RW, 0x00000000},
+{0x6B8, "RXUO", "Receive unknown OP code counter ", ACC_RW, 0x00000000},
+{0x6BC, "RALN", "Receive alignment error counter ", ACC_RW, 0x00000000},
+{0x6C0, "RFLR", "Receive frame length error counter ", ACC_RW, 0x00000000},
+{0x6C4, "RCDE", "Receive code error counter ", ACC_RW, 0x00000000},
+{0x6C8, "RCSE", "Receive carrier sense error counter", ACC_RW, 0x00000000},
+{0x6CC, "RUND", "Receive undersize packet counter", ACC_RW, 0x00000000},
+{0x6D0, "ROVR", "Receive oversize packet counter ", ACC_RW, 0x00000000},
+{0x6D4, "RFRG", "Receive fragments counter", ACC_RW, 0x00000000},
+{0x6D8, "RJBR", "Receive jabber counter ", ACC_RW, 0x00000000},
+{0x6DC, "RDRP", "Receive drop counter", ACC_RW, 0x00000000},
+
+/* eTSEC Transmit Counters */
+
+{0x6E0, "TBYT", "Transmit byte counter", ACC_RW, 0x00000000},
+{0x6E4, "TPKT", "Transmit packet counter", ACC_RW, 0x00000000},
+{0x6E8, "TMCA", "Transmit multicast packet counter ", ACC_RW, 0x00000000},
+{0x6EC, "TBCA", "Transmit broadcast packet counter ", ACC_RW, 0x00000000},
+{0x6F0, "TXPF", "Transmit PAUSE control frame counter ", ACC_RW, 0x00000000},
+{0x6F4, "TDFR", "Transmit deferral packet counter ", ACC_RW, 0x00000000},
+{0x6F8, "TEDF", "Transmit excessive deferral packet counter ", ACC_RW, 0x00000000},
+{0x6FC, "TSCL", "Transmit single collision packet counter", ACC_RW, 0x00000000},
+{0x700, "TMCL", "Transmit multiple collision packet counter", ACC_RW, 0x00000000},
+{0x704, "TLCL", "Transmit late collision packet counter", ACC_RW, 0x00000000},
+{0x708, "TXCL", "Transmit excessive collision packet counter", ACC_RW, 0x00000000},
+{0x70C, "TNCL", "Transmit total collision counter ", ACC_RW, 0x00000000},
+{0x714, "TDRP", "Transmit drop frame counter", ACC_RW, 0x00000000},
+{0x718, "TJBR", "Transmit jabber frame counter ", ACC_RW, 0x00000000},
+{0x71C, "TFCS", "Transmit FCS error counter", ACC_RW, 0x00000000},
+{0x720, "TXCF", "Transmit control frame counter ", ACC_RW, 0x00000000},
+{0x724, "TOVR", "Transmit oversize frame counter", ACC_RW, 0x00000000},
+{0x728, "TUND", "Transmit undersize frame counter ", ACC_RW, 0x00000000},
+{0x72C, "TFRG", "Transmit fragments frame counter ", ACC_RW, 0x00000000},
+
+/* eTSEC Counter Control and TOE Statistics Registers */
+
+{0x730, "CAR1", "Carry register one register", ACC_W1C, 0x00000000},
+{0x734, "CAR2", "Carry register two register ", ACC_W1C, 0x00000000},
+{0x738, "CAM1", "Carry register one mask register ", ACC_RW, 0xFE03FFFF},
+{0x73C, "CAM2", "Carry register two mask register ", ACC_RW, 0x000FFFFD},
+{0x740, "RREJ", "Receive filer rejected packet counter", ACC_RW, 0x00000000},
+
+/* Hash Function Registers */
+
+{0x800, "IGADDR0", "Individual/group address register 0", ACC_RW, 0x00000000},
+{0x804, "IGADDR1", "Individual/group address register 1", ACC_RW, 0x00000000},
+{0x808, "IGADDR2", "Individual/group address register 2", ACC_RW, 0x00000000},
+{0x80C, "IGADDR3", "Individual/group address register 3", ACC_RW, 0x00000000},
+{0x810, "IGADDR4", "Individual/group address register 4", ACC_RW, 0x00000000},
+{0x814, "IGADDR5", "Individual/group address register 5", ACC_RW, 0x00000000},
+{0x818, "IGADDR6", "Individual/group address register 6", ACC_RW, 0x00000000},
+{0x81C, "IGADDR7", "Individual/group address register 7", ACC_RW, 0x00000000},
+{0x880, "GADDR0", "Group address register 0", ACC_RW, 0x00000000},
+{0x884, "GADDR1", "Group address register 1", ACC_RW, 0x00000000},
+{0x888, "GADDR2", "Group address register 2", ACC_RW, 0x00000000},
+{0x88C, "GADDR3", "Group address register 3", ACC_RW, 0x00000000},
+{0x890, "GADDR4", "Group address register 4", ACC_RW, 0x00000000},
+{0x894, "GADDR5", "Group address register 5", ACC_RW, 0x00000000},
+{0x898, "GADDR6", "Group address register 6", ACC_RW, 0x00000000},
+{0x89C, "GADDR7", "Group address register 7", ACC_RW, 0x00000000},
+
+/* eTSEC DMA Attribute Registers */
+
+{0xBF8, "ATTR", "Attribute register", ACC_RW, 0x00000000},
+{0xBFC, "ATTRELI", "Attribute extract length and extract index register", ACC_RW, 0x00000000},
+
+
+/* eTSEC Lossless Flow Control Registers */
+
+{0xC00, "RQPRM0", "Receive Queue Parameters register 0 ", ACC_RW, 0x00000000},
+{0xC04, "RQPRM1", "Receive Queue Parameters register 1 ", ACC_RW, 0x00000000},
+{0xC08, "RQPRM2", "Receive Queue Parameters register 2 ", ACC_RW, 0x00000000},
+{0xC0C, "RQPRM3", "Receive Queue Parameters register 3 ", ACC_RW, 0x00000000},
+{0xC10, "RQPRM4", "Receive Queue Parameters register 4 ", ACC_RW, 0x00000000},
+{0xC14, "RQPRM5", "Receive Queue Parameters register 5 ", ACC_RW, 0x00000000},
+{0xC18, "RQPRM6", "Receive Queue Parameters register 6 ", ACC_RW, 0x00000000},
+{0xC1C, "RQPRM7", "Receive Queue Parameters register 7 ", ACC_RW, 0x00000000},
+{0xC44, "RFBPTR0", "Last Free RxBD pointer for ring 0", ACC_RW, 0x00000000},
+{0xC4C, "RFBPTR1", "Last Free RxBD pointer for ring 1", ACC_RW, 0x00000000},
+{0xC54, "RFBPTR2", "Last Free RxBD pointer for ring 2", ACC_RW, 0x00000000},
+{0xC5C, "RFBPTR3", "Last Free RxBD pointer for ring 3", ACC_RW, 0x00000000},
+{0xC64, "RFBPTR4", "Last Free RxBD pointer for ring 4", ACC_RW, 0x00000000},
+{0xC6C, "RFBPTR5", "Last Free RxBD pointer for ring 5", ACC_RW, 0x00000000},
+{0xC74, "RFBPTR6", "Last Free RxBD pointer for ring 6", ACC_RW, 0x00000000},
+{0xC7C, "RFBPTR7", "Last Free RxBD pointer for ring 7", ACC_RW, 0x00000000},
+
+/* eTSEC Future Expansion Space */
+
+/* Reserved*/
+
+/* eTSEC IEEE 1588 Registers */
+
+{0xE00, "TMR_CTRL", "Timer control register", ACC_RW, 0x00010001},
+{0xE04, "TMR_TEVENT", "time stamp event register", ACC_W1C, 0x00000000},
+{0xE08, "TMR_TEMASK", "Timer event mask register", ACC_RW, 0x00000000},
+{0xE0C, "TMR_PEVENT", "time stamp event register", ACC_RW, 0x00000000},
+{0xE10, "TMR_PEMASK", "Timer event mask register", ACC_RW, 0x00000000},
+{0xE14, "TMR_STAT", "time stamp status register", ACC_RW, 0x00000000},
+{0xE18, "TMR_CNT_H", "timer counter high register", ACC_RW, 0x00000000},
+{0xE1C, "TMR_CNT_L", "timer counter low register", ACC_RW, 0x00000000},
+{0xE20, "TMR_ADD", "Timer drift compensation addend register", ACC_RW, 0x00000000},
+{0xE24, "TMR_ACC", "Timer accumulator register", ACC_RW, 0x00000000},
+{0xE28, "TMR_PRSC", "Timer prescale", ACC_RW, 0x00000002},
+{0xE30, "TMROFF_H", "Timer offset high", ACC_RW, 0x00000000},
+{0xE34, "TMROFF_L", "Timer offset low", ACC_RW, 0x00000000},
+{0xE40, "TMR_ALARM1_H", "Timer alarm 1 high register", ACC_RW, 0xFFFFFFFF},
+{0xE44, "TMR_ALARM1_L", "Timer alarm 1 high register", ACC_RW, 0xFFFFFFFF},
+{0xE48, "TMR_ALARM2_H", "Timer alarm 2 high register", ACC_RW, 0xFFFFFFFF},
+{0xE4C, "TMR_ALARM2_L", "Timer alarm 2 high register", ACC_RW, 0xFFFFFFFF},
+{0xE80, "TMR_FIPER1", "Timer fixed period interval", ACC_RW, 0xFFFFFFFF},
+{0xE84, "TMR_FIPER2", "Timer fixed period interval", ACC_RW, 0xFFFFFFFF},
+{0xE88, "TMR_FIPER3", "Timer fixed period interval", ACC_RW, 0xFFFFFFFF},
+{0xEA0, "TMR_ETTS1_H", "Time stamp of general purpose external trigger ", ACC_RW, 0x00000000},
+{0xEA4, "TMR_ETTS1_L", "Time stamp of general purpose external trigger", ACC_RW, 0x00000000},
+{0xEA8, "TMR_ETTS2_H", "Time stamp of general purpose external trigger ", ACC_RW, 0x00000000},
+{0xEAC, "TMR_ETTS2_L", "Time stamp of general purpose external trigger", ACC_RW, 0x00000000},
+
+/* End Of Table */
+{0x0, 0x0, 0x0, 0x0, 0x0}
+};
diff --git a/hw/net/fsl_etsec/registers.h b/hw/net/fsl_etsec/registers.h
new file mode 100644
index 0000000000..7ad7686470
--- /dev/null
+++ b/hw/net/fsl_etsec/registers.h
@@ -0,0 +1,320 @@
+/*
+ * QEMU Freescale eTSEC Emulator
+ *
+ * Copyright (c) 2011-2013 AdaCore
+ *
+ * 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.
+ */
+#ifndef _ETSEC_REGISTERS_H_
+#define _ETSEC_REGISTERS_H_
+
+#include <stdint.h>
+
+enum eTSEC_Register_Access_Type {
+ ACC_RW = 1, /* Read/Write */
+ ACC_RO = 2, /* Read Only */
+ ACC_WO = 3, /* Write Only */
+ ACC_W1C = 4, /* Write 1 to clear */
+ ACC_UNKNOWN = 5 /* Unknown register*/
+};
+
+typedef struct eTSEC_Register_Definition {
+ uint32_t offset;
+ const char *name;
+ const char *desc;
+ enum eTSEC_Register_Access_Type access;
+ uint32_t reset;
+} eTSEC_Register_Definition;
+
+extern const eTSEC_Register_Definition eTSEC_registers_def[];
+
+#define DMACTRL_LE (1 << 15)
+#define DMACTRL_GRS (1 << 4)
+#define DMACTRL_GTS (1 << 3)
+#define DMACTRL_WOP (1 << 0)
+
+#define IEVENT_PERR (1 << 0)
+#define IEVENT_DPE (1 << 1)
+#define IEVENT_FIQ (1 << 2)
+#define IEVENT_FIR (1 << 3)
+#define IEVENT_FGPI (1 << 4)
+#define IEVENT_RXF (1 << 7)
+#define IEVENT_GRSC (1 << 8)
+#define IEVENT_MMRW (1 << 9)
+#define IEVENT_MMRD (1 << 10)
+#define IEVENT_MAG (1 << 11)
+#define IEVENT_RXB (1 << 15)
+#define IEVENT_XFUN (1 << 16)
+#define IEVENT_CRL (1 << 17)
+#define IEVENT_LC (1 << 18)
+#define IEVENT_TXF (1 << 20)
+#define IEVENT_TXB (1 << 21)
+#define IEVENT_TXE (1 << 22)
+#define IEVENT_TXC (1 << 23)
+#define IEVENT_BABT (1 << 24)
+#define IEVENT_GTSC (1 << 25)
+#define IEVENT_MSRO (1 << 26)
+#define IEVENT_EBERR (1 << 28)
+#define IEVENT_BSY (1 << 29)
+#define IEVENT_RXC (1 << 30)
+#define IEVENT_BABR (1 << 31)
+
+#define IMASK_RXFEN (1 << 7)
+#define IMASK_GRSCEN (1 << 8)
+#define IMASK_RXBEN (1 << 15)
+#define IMASK_TXFEN (1 << 20)
+#define IMASK_TXBEN (1 << 21)
+#define IMASK_GTSCEN (1 << 25)
+
+#define MACCFG1_TX_EN (1 << 0)
+#define MACCFG1_RX_EN (1 << 2)
+
+#define MACCFG2_CRC_EN (1 << 1)
+#define MACCFG2_PADCRC (1 << 2)
+
+#define MIIMCOM_READ (1 << 0)
+#define MIIMCOM_SCAN (1 << 1)
+
+#define RCTRL_PRSDEP_MASK (0x3)
+#define RCTRL_PRSDEP_OFFSET (6)
+#define RCTRL_RSF (1 << 2)
+
+/* Index of each register */
+
+#define TSEC_ID (0x000 / 4)
+#define TSEC_ID2 (0x004 / 4)
+#define IEVENT (0x010 / 4)
+#define IMASK (0x014 / 4)
+#define EDIS (0x018 / 4)
+#define ECNTRL (0x020 / 4)
+#define PTV (0x028 / 4)
+#define DMACTRL (0x02C / 4)
+#define TBIPA (0x030 / 4)
+#define TCTRL (0x100 / 4)
+#define TSTAT (0x104 / 4)
+#define DFVLAN (0x108 / 4)
+#define TXIC (0x110 / 4)
+#define TQUEUE (0x114 / 4)
+#define TR03WT (0x140 / 4)
+#define TR47WT (0x144 / 4)
+#define TBDBPH (0x180 / 4)
+#define TBPTR0 (0x184 / 4)
+#define TBPTR1 (0x18C / 4)
+#define TBPTR2 (0x194 / 4)
+#define TBPTR3 (0x19C / 4)
+#define TBPTR4 (0x1A4 / 4)
+#define TBPTR5 (0x1AC / 4)
+#define TBPTR6 (0x1B4 / 4)
+#define TBPTR7 (0x1BC / 4)
+#define TBASEH (0x200 / 4)
+#define TBASE0 (0x204 / 4)
+#define TBASE1 (0x20C / 4)
+#define TBASE2 (0x214 / 4)
+#define TBASE3 (0x21C / 4)
+#define TBASE4 (0x224 / 4)
+#define TBASE5 (0x22C / 4)
+#define TBASE6 (0x234 / 4)
+#define TBASE7 (0x23C / 4)
+#define TMR_TXTS1_ID (0x280 / 4)
+#define TMR_TXTS2_ID (0x284 / 4)
+#define TMR_TXTS1_H (0x2C0 / 4)
+#define TMR_TXTS1_L (0x2C4 / 4)
+#define TMR_TXTS2_H (0x2C8 / 4)
+#define TMR_TXTS2_L (0x2CC / 4)
+#define RCTRL (0x300 / 4)
+#define RSTAT (0x304 / 4)
+#define RXIC (0x310 / 4)
+#define RQUEUE (0x314 / 4)
+#define RBIFX (0x330 / 4)
+#define RQFAR (0x334 / 4)
+#define RQFCR (0x338 / 4)
+#define RQFPR (0x33C / 4)
+#define MRBLR (0x340 / 4)
+#define RBDBPH (0x380 / 4)
+#define RBPTR0 (0x384 / 4)
+#define RBPTR1 (0x38C / 4)
+#define RBPTR2 (0x394 / 4)
+#define RBPTR3 (0x39C / 4)
+#define RBPTR4 (0x3A4 / 4)
+#define RBPTR5 (0x3AC / 4)
+#define RBPTR6 (0x3B4 / 4)
+#define RBPTR7 (0x3BC / 4)
+#define RBASEH (0x400 / 4)
+#define RBASE0 (0x404 / 4)
+#define RBASE1 (0x40C / 4)
+#define RBASE2 (0x414 / 4)
+#define RBASE3 (0x41C / 4)
+#define RBASE4 (0x424 / 4)
+#define RBASE5 (0x42C / 4)
+#define RBASE6 (0x434 / 4)
+#define RBASE7 (0x43C / 4)
+#define TMR_RXTS_H (0x4C0 / 4)
+#define TMR_RXTS_L (0x4C4 / 4)
+#define MACCFG1 (0x500 / 4)
+#define MACCFG2 (0x504 / 4)
+#define IPGIFG (0x508 / 4)
+#define HAFDUP (0x50C / 4)
+#define MAXFRM (0x510 / 4)
+#define MIIMCFG (0x520 / 4)
+#define MIIMCOM (0x524 / 4)
+#define MIIMADD (0x528 / 4)
+#define MIIMCON (0x52C / 4)
+#define MIIMSTAT (0x530 / 4)
+#define MIIMIND (0x534 / 4)
+#define IFSTAT (0x53C / 4)
+#define MACSTNADDR1 (0x540 / 4)
+#define MACSTNADDR2 (0x544 / 4)
+#define MAC01ADDR1 (0x548 / 4)
+#define MAC01ADDR2 (0x54C / 4)
+#define MAC02ADDR1 (0x550 / 4)
+#define MAC02ADDR2 (0x554 / 4)
+#define MAC03ADDR1 (0x558 / 4)
+#define MAC03ADDR2 (0x55C / 4)
+#define MAC04ADDR1 (0x560 / 4)
+#define MAC04ADDR2 (0x564 / 4)
+#define MAC05ADDR1 (0x568 / 4)
+#define MAC05ADDR2 (0x56C / 4)
+#define MAC06ADDR1 (0x570 / 4)
+#define MAC06ADDR2 (0x574 / 4)
+#define MAC07ADDR1 (0x578 / 4)
+#define MAC07ADDR2 (0x57C / 4)
+#define MAC08ADDR1 (0x580 / 4)
+#define MAC08ADDR2 (0x584 / 4)
+#define MAC09ADDR1 (0x588 / 4)
+#define MAC09ADDR2 (0x58C / 4)
+#define MAC10ADDR1 (0x590 / 4)
+#define MAC10ADDR2 (0x594 / 4)
+#define MAC11ADDR1 (0x598 / 4)
+#define MAC11ADDR2 (0x59C / 4)
+#define MAC12ADDR1 (0x5A0 / 4)
+#define MAC12ADDR2 (0x5A4 / 4)
+#define MAC13ADDR1 (0x5A8 / 4)
+#define MAC13ADDR2 (0x5AC / 4)
+#define MAC14ADDR1 (0x5B0 / 4)
+#define MAC14ADDR2 (0x5B4 / 4)
+#define MAC15ADDR1 (0x5B8 / 4)
+#define MAC15ADDR2 (0x5BC / 4)
+#define TR64 (0x680 / 4)
+#define TR127 (0x684 / 4)
+#define TR255 (0x688 / 4)
+#define TR511 (0x68C / 4)
+#define TR1K (0x690 / 4)
+#define TRMAX (0x694 / 4)
+#define TRMGV (0x698 / 4)
+#define RBYT (0x69C / 4)
+#define RPKT (0x6A0 / 4)
+#define RFCS (0x6A4 / 4)
+#define RMCA (0x6A8 / 4)
+#define RBCA (0x6AC / 4)
+#define RXCF (0x6B0 / 4)
+#define RXPF (0x6B4 / 4)
+#define RXUO (0x6B8 / 4)
+#define RALN (0x6BC / 4)
+#define RFLR (0x6C0 / 4)
+#define RCDE (0x6C4 / 4)
+#define RCSE (0x6C8 / 4)
+#define RUND (0x6CC / 4)
+#define ROVR (0x6D0 / 4)
+#define RFRG (0x6D4 / 4)
+#define RJBR (0x6D8 / 4)
+#define RDRP (0x6DC / 4)
+#define TBYT (0x6E0 / 4)
+#define TPKT (0x6E4 / 4)
+#define TMCA (0x6E8 / 4)
+#define TBCA (0x6EC / 4)
+#define TXPF (0x6F0 / 4)
+#define TDFR (0x6F4 / 4)
+#define TEDF (0x6F8 / 4)
+#define TSCL (0x6FC / 4)
+#define TMCL (0x700 / 4)
+#define TLCL (0x704 / 4)
+#define TXCL (0x708 / 4)
+#define TNCL (0x70C / 4)
+#define TDRP (0x714 / 4)
+#define TJBR (0x718 / 4)
+#define TFCS (0x71C / 4)
+#define TXCF (0x720 / 4)
+#define TOVR (0x724 / 4)
+#define TUND (0x728 / 4)
+#define TFRG (0x72C / 4)
+#define CAR1 (0x730 / 4)
+#define CAR2 (0x734 / 4)
+#define CAM1 (0x738 / 4)
+#define CAM2 (0x73C / 4)
+#define RREJ (0x740 / 4)
+#define IGADDR0 (0x800 / 4)
+#define IGADDR1 (0x804 / 4)
+#define IGADDR2 (0x808 / 4)
+#define IGADDR3 (0x80C / 4)
+#define IGADDR4 (0x810 / 4)
+#define IGADDR5 (0x814 / 4)
+#define IGADDR6 (0x818 / 4)
+#define IGADDR7 (0x81C / 4)
+#define GADDR0 (0x880 / 4)
+#define GADDR1 (0x884 / 4)
+#define GADDR2 (0x888 / 4)
+#define GADDR3 (0x88C / 4)
+#define GADDR4 (0x890 / 4)
+#define GADDR5 (0x894 / 4)
+#define GADDR6 (0x898 / 4)
+#define GADDR7 (0x89C / 4)
+#define ATTR (0xBF8 / 4)
+#define ATTRELI (0xBFC / 4)
+#define RQPRM0 (0xC00 / 4)
+#define RQPRM1 (0xC04 / 4)
+#define RQPRM2 (0xC08 / 4)
+#define RQPRM3 (0xC0C / 4)
+#define RQPRM4 (0xC10 / 4)
+#define RQPRM5 (0xC14 / 4)
+#define RQPRM6 (0xC18 / 4)
+#define RQPRM7 (0xC1C / 4)
+#define RFBPTR0 (0xC44 / 4)
+#define RFBPTR1 (0xC4C / 4)
+#define RFBPTR2 (0xC54 / 4)
+#define RFBPTR3 (0xC5C / 4)
+#define RFBPTR4 (0xC64 / 4)
+#define RFBPTR5 (0xC6C / 4)
+#define RFBPTR6 (0xC74 / 4)
+#define RFBPTR7 (0xC7C / 4)
+#define TMR_CTRL (0xE00 / 4)
+#define TMR_TEVENT (0xE04 / 4)
+#define TMR_TEMASK (0xE08 / 4)
+#define TMR_PEVENT (0xE0C / 4)
+#define TMR_PEMASK (0xE10 / 4)
+#define TMR_STAT (0xE14 / 4)
+#define TMR_CNT_H (0xE18 / 4)
+#define TMR_CNT_L (0xE1C / 4)
+#define TMR_ADD (0xE20 / 4)
+#define TMR_ACC (0xE24 / 4)
+#define TMR_PRSC (0xE28 / 4)
+#define TMROFF_H (0xE30 / 4)
+#define TMROFF_L (0xE34 / 4)
+#define TMR_ALARM1_H (0xE40 / 4)
+#define TMR_ALARM1_L (0xE44 / 4)
+#define TMR_ALARM2_H (0xE48 / 4)
+#define TMR_ALARM2_L (0xE4C / 4)
+#define TMR_FIPER1 (0xE80 / 4)
+#define TMR_FIPER2 (0xE84 / 4)
+#define TMR_FIPER3 (0xE88 / 4)
+#define TMR_ETTS1_H (0xEA0 / 4)
+#define TMR_ETTS1_L (0xEA4 / 4)
+#define TMR_ETTS2_H (0xEA8 / 4)
+#define TMR_ETTS2_L (0xEAC / 4)
+
+#endif /* ! _ETSEC_REGISTERS_H_ */
diff --git a/hw/net/fsl_etsec/rings.c b/hw/net/fsl_etsec/rings.c
new file mode 100644
index 0000000000..77602722b3
--- /dev/null
+++ b/hw/net/fsl_etsec/rings.c
@@ -0,0 +1,650 @@
+/*
+ * QEMU Freescale eTSEC Emulator
+ *
+ * Copyright (c) 2011-2013 AdaCore
+ *
+ * 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.
+ */
+#include "net/checksum.h"
+
+#include "etsec.h"
+#include "registers.h"
+
+/* #define ETSEC_RING_DEBUG */
+/* #define HEX_DUMP */
+/* #define DEBUG_BD */
+
+#ifdef ETSEC_RING_DEBUG
+static const int debug_etsec = 1;
+#else
+static const int debug_etsec;
+#endif
+
+#define RING_DEBUG(fmt, ...) do { \
+ if (debug_etsec) { \
+ qemu_log(fmt , ## __VA_ARGS__); \
+ } \
+ } while (0)
+
+#ifdef DEBUG_BD
+
+static void print_tx_bd_flags(uint16_t flags)
+{
+ qemu_log(" Ready: %d\n", !!(flags & BD_TX_READY));
+ qemu_log(" PAD/CRC: %d\n", !!(flags & BD_TX_PADCRC));
+ qemu_log(" Wrap: %d\n", !!(flags & BD_WRAP));
+ qemu_log(" Interrupt: %d\n", !!(flags & BD_INTERRUPT));
+ qemu_log(" Last in frame: %d\n", !!(flags & BD_LAST));
+ qemu_log(" Tx CRC: %d\n", !!(flags & BD_TX_TC));
+ qemu_log(" User-defined preamble / defer: %d\n",
+ !!(flags & BD_TX_PREDEF));
+ qemu_log(" Huge frame enable / Late collision: %d\n",
+ !!(flags & BD_TX_HFELC));
+ qemu_log(" Control frame / Retransmission Limit: %d\n",
+ !!(flags & BD_TX_CFRL));
+ qemu_log(" Retry count: %d\n",
+ (flags >> BD_TX_RC_OFFSET) & BD_TX_RC_MASK);
+ qemu_log(" Underrun / TCP/IP off-load enable: %d\n",
+ !!(flags & BD_TX_TOEUN));
+ qemu_log(" Truncation: %d\n", !!(flags & BD_TX_TR));
+}
+
+static void print_rx_bd_flags(uint16_t flags)
+{
+ qemu_log(" Empty: %d\n", !!(flags & BD_RX_EMPTY));
+ qemu_log(" Receive software ownership: %d\n", !!(flags & BD_RX_RO1));
+ qemu_log(" Wrap: %d\n", !!(flags & BD_WRAP));
+ qemu_log(" Interrupt: %d\n", !!(flags & BD_INTERRUPT));
+ qemu_log(" Last in frame: %d\n", !!(flags & BD_LAST));
+ qemu_log(" First in frame: %d\n", !!(flags & BD_RX_FIRST));
+ qemu_log(" Miss: %d\n", !!(flags & BD_RX_MISS));
+ qemu_log(" Broadcast: %d\n", !!(flags & BD_RX_BROADCAST));
+ qemu_log(" Multicast: %d\n", !!(flags & BD_RX_MULTICAST));
+ qemu_log(" Rx frame length violation: %d\n", !!(flags & BD_RX_LG));
+ qemu_log(" Rx non-octet aligned frame: %d\n", !!(flags & BD_RX_NO));
+ qemu_log(" Short frame: %d\n", !!(flags & BD_RX_SH));
+ qemu_log(" Rx CRC Error: %d\n", !!(flags & BD_RX_CR));
+ qemu_log(" Overrun: %d\n", !!(flags & BD_RX_OV));
+ qemu_log(" Truncation: %d\n", !!(flags & BD_RX_TR));
+}
+
+
+static void print_bd(eTSEC_rxtx_bd bd, int mode, uint32_t index)
+{
+ qemu_log("eTSEC %s Data Buffer Descriptor (%u)\n",
+ mode == eTSEC_TRANSMIT ? "Transmit" : "Receive",
+ index);
+ qemu_log(" Flags : 0x%04x\n", bd.flags);
+ if (mode == eTSEC_TRANSMIT) {
+ print_tx_bd_flags(bd.flags);
+ } else {
+ print_rx_bd_flags(bd.flags);
+ }
+ qemu_log(" Length : 0x%04x\n", bd.length);
+ qemu_log(" Pointer : 0x%08x\n", bd.bufptr);
+}
+
+#endif /* DEBUG_BD */
+
+static void read_buffer_descriptor(eTSEC *etsec,
+ hwaddr addr,
+ eTSEC_rxtx_bd *bd)
+{
+ assert(bd != NULL);
+
+ RING_DEBUG("READ Buffer Descriptor @ 0x" TARGET_FMT_plx"\n", addr);
+ cpu_physical_memory_read(addr,
+ bd,
+ sizeof(eTSEC_rxtx_bd));
+
+ if (etsec->regs[DMACTRL].value & DMACTRL_LE) {
+ bd->flags = lduw_le_p(&bd->flags);
+ bd->length = lduw_le_p(&bd->length);
+ bd->bufptr = ldl_le_p(&bd->bufptr);
+ } else {
+ bd->flags = lduw_be_p(&bd->flags);
+ bd->length = lduw_be_p(&bd->length);
+ bd->bufptr = ldl_be_p(&bd->bufptr);
+ }
+}
+
+static void write_buffer_descriptor(eTSEC *etsec,
+ hwaddr addr,
+ eTSEC_rxtx_bd *bd)
+{
+ assert(bd != NULL);
+
+ if (etsec->regs[DMACTRL].value & DMACTRL_LE) {
+ stw_le_p(&bd->flags, bd->flags);
+ stw_le_p(&bd->length, bd->length);
+ stl_le_p(&bd->bufptr, bd->bufptr);
+ } else {
+ stw_be_p(&bd->flags, bd->flags);
+ stw_be_p(&bd->length, bd->length);
+ stl_be_p(&bd->bufptr, bd->bufptr);
+ }
+
+ RING_DEBUG("Write Buffer Descriptor @ 0x" TARGET_FMT_plx"\n", addr);
+ cpu_physical_memory_write(addr,
+ bd,
+ sizeof(eTSEC_rxtx_bd));
+}
+
+static void ievent_set(eTSEC *etsec,
+ uint32_t flags)
+{
+ etsec->regs[IEVENT].value |= flags;
+
+ if ((flags & IEVENT_TXB && etsec->regs[IMASK].value & IMASK_TXBEN)
+ || (flags & IEVENT_TXF && etsec->regs[IMASK].value & IMASK_TXFEN)) {
+ qemu_irq_raise(etsec->tx_irq);
+ RING_DEBUG("%s Raise Tx IRQ\n", __func__);
+ }
+
+ if ((flags & IEVENT_RXB && etsec->regs[IMASK].value & IMASK_RXBEN)
+ || (flags & IEVENT_RXF && etsec->regs[IMASK].value & IMASK_RXFEN)) {
+ qemu_irq_pulse(etsec->rx_irq);
+ RING_DEBUG("%s Raise Rx IRQ\n", __func__);
+ }
+}
+
+static void tx_padding_and_crc(eTSEC *etsec, uint32_t min_frame_len)
+{
+ int add = min_frame_len - etsec->tx_buffer_len;
+
+ /* Padding */
+ if (add > 0) {
+ RING_DEBUG("pad:%u\n", add);
+ etsec->tx_buffer = g_realloc(etsec->tx_buffer,
+ etsec->tx_buffer_len + add);
+
+ memset(etsec->tx_buffer + etsec->tx_buffer_len, 0x0, add);
+ etsec->tx_buffer_len += add;
+ }
+
+ /* Never add CRC in QEMU */
+}
+
+static void process_tx_fcb(eTSEC *etsec)
+{
+ uint8_t flags = (uint8_t)(*etsec->tx_buffer);
+ /* L3 header offset from start of frame */
+ uint8_t l3_header_offset = (uint8_t)*(etsec->tx_buffer + 3);
+ /* L4 header offset from start of L3 header */
+ uint8_t l4_header_offset = (uint8_t)*(etsec->tx_buffer + 2);
+ /* L3 header */
+ uint8_t *l3_header = etsec->tx_buffer + 8 + l3_header_offset;
+ /* L4 header */
+ uint8_t *l4_header = l3_header + l4_header_offset;
+
+ /* if packet is IP4 and IP checksum is requested */
+ if (flags & FCB_TX_IP && flags & FCB_TX_CIP) {
+ /* do IP4 checksum (TODO This funtion does TCP/UDP checksum but not sure
+ * if it also does IP4 checksum. */
+ net_checksum_calculate(etsec->tx_buffer + 8,
+ etsec->tx_buffer_len - 8);
+ }
+ /* TODO Check the correct usage of the PHCS field of the FCB in case the NPH
+ * flag is on */
+
+ /* if packet is IP4 and TCP or UDP */
+ if (flags & FCB_TX_IP && flags & FCB_TX_TUP) {
+ /* if UDP */
+ if (flags & FCB_TX_UDP) {
+ /* if checksum is requested */
+ if (flags & FCB_TX_CTU) {
+ /* do UDP checksum */
+
+ net_checksum_calculate(etsec->tx_buffer + 8,
+ etsec->tx_buffer_len - 8);
+ } else {
+ /* set checksum field to 0 */
+ l4_header[6] = 0;
+ l4_header[7] = 0;
+ }
+ } else if (flags & FCB_TX_CTU) { /* if TCP and checksum is requested */
+ /* do TCP checksum */
+ net_checksum_calculate(etsec->tx_buffer + 8,
+ etsec->tx_buffer_len - 8);
+ }
+ }
+}
+
+static void process_tx_bd(eTSEC *etsec,
+ eTSEC_rxtx_bd *bd)
+{
+ uint8_t *tmp_buff = NULL;
+ hwaddr tbdbth = (hwaddr)(etsec->regs[TBDBPH].value & 0xF) << 32;
+
+ if (bd->length == 0) {
+ /* ERROR */
+ return;
+ }
+
+ if (etsec->tx_buffer_len == 0) {
+ /* It's the first BD */
+ etsec->first_bd = *bd;
+ }
+
+ /* TODO: if TxBD[TOE/UN] skip the Tx Frame Control Block*/
+
+ /* Load this Data Buffer */
+ etsec->tx_buffer = g_realloc(etsec->tx_buffer,
+ etsec->tx_buffer_len + bd->length);
+ tmp_buff = etsec->tx_buffer + etsec->tx_buffer_len;
+ cpu_physical_memory_read(bd->bufptr + tbdbth, tmp_buff, bd->length);
+
+ /* Update buffer length */
+ etsec->tx_buffer_len += bd->length;
+
+
+ if (etsec->tx_buffer_len != 0 && (bd->flags & BD_LAST)) {
+ if (etsec->regs[MACCFG1].value & MACCFG1_TX_EN) {
+ /* MAC Transmit enabled */
+
+ /* Process offload Tx FCB */
+ if (etsec->first_bd.flags & BD_TX_TOEUN) {
+ process_tx_fcb(etsec);
+ }
+
+ if (etsec->first_bd.flags & BD_TX_PADCRC
+ || etsec->regs[MACCFG2].value & MACCFG2_PADCRC) {
+
+ /* Padding and CRC (Padding implies CRC) */
+ tx_padding_and_crc(etsec, 64);
+
+ } else if (etsec->first_bd.flags & BD_TX_TC
+ || etsec->regs[MACCFG2].value & MACCFG2_CRC_EN) {
+
+ /* Only CRC */
+ /* Never add CRC in QEMU */
+ }
+
+#if defined(HEX_DUMP)
+ qemu_log("eTSEC Send packet size:%d\n", etsec->tx_buffer_len);
+ qemu_hexdump(etsec->tx_buffer, stderr, "", etsec->tx_buffer_len);
+#endif /* ETSEC_RING_DEBUG */
+
+ if (etsec->first_bd.flags & BD_TX_TOEUN) {
+ qemu_send_packet(qemu_get_queue(etsec->nic),
+ etsec->tx_buffer + 8,
+ etsec->tx_buffer_len - 8);
+ } else {
+ qemu_send_packet(qemu_get_queue(etsec->nic),
+ etsec->tx_buffer,
+ etsec->tx_buffer_len);
+ }
+
+ }
+
+ etsec->tx_buffer_len = 0;
+
+ if (bd->flags & BD_INTERRUPT) {
+ ievent_set(etsec, IEVENT_TXF);
+ }
+ } else {
+ if (bd->flags & BD_INTERRUPT) {
+ ievent_set(etsec, IEVENT_TXB);
+ }
+ }
+
+ /* Update DB flags */
+
+ /* Clear Ready */
+ bd->flags &= ~BD_TX_READY;
+
+ /* Clear Defer */
+ bd->flags &= ~BD_TX_PREDEF;
+
+ /* Clear Late Collision */
+ bd->flags &= ~BD_TX_HFELC;
+
+ /* Clear Retransmission Limit */
+ bd->flags &= ~BD_TX_CFRL;
+
+ /* Clear Retry Count */
+ bd->flags &= ~(BD_TX_RC_MASK << BD_TX_RC_OFFSET);
+
+ /* Clear Underrun */
+ bd->flags &= ~BD_TX_TOEUN;
+
+ /* Clear Truncation */
+ bd->flags &= ~BD_TX_TR;
+}
+
+void etsec_walk_tx_ring(eTSEC *etsec, int ring_nbr)
+{
+ hwaddr ring_base = 0;
+ hwaddr bd_addr = 0;
+ eTSEC_rxtx_bd bd;
+ uint16_t bd_flags;
+
+ if (!(etsec->regs[MACCFG1].value & MACCFG1_TX_EN)) {
+ RING_DEBUG("%s: MAC Transmit not enabled\n", __func__);
+ return;
+ }
+
+ ring_base = (hwaddr)(etsec->regs[TBASEH].value & 0xF) << 32;
+ ring_base += etsec->regs[TBASE0 + ring_nbr].value & ~0x7;
+ bd_addr = etsec->regs[TBPTR0 + ring_nbr].value & ~0x7;
+
+ do {
+ read_buffer_descriptor(etsec, bd_addr, &bd);
+
+#ifdef DEBUG_BD
+ print_bd(bd,
+ eTSEC_TRANSMIT,
+ (bd_addr - ring_base) / sizeof(eTSEC_rxtx_bd));
+
+#endif /* DEBUG_BD */
+
+ /* Save flags before BD update */
+ bd_flags = bd.flags;
+
+ if (bd_flags & BD_TX_READY) {
+ process_tx_bd(etsec, &bd);
+
+ /* Write back BD after update */
+ write_buffer_descriptor(etsec, bd_addr, &bd);
+ }
+
+ /* Wrap or next BD */
+ if (bd_flags & BD_WRAP) {
+ bd_addr = ring_base;
+ } else {
+ bd_addr += sizeof(eTSEC_rxtx_bd);
+ }
+
+ } while (bd_addr != ring_base);
+
+ bd_addr = ring_base;
+
+ /* Save the Buffer Descriptor Pointers to current bd */
+ etsec->regs[TBPTR0 + ring_nbr].value = bd_addr;
+
+ /* Set transmit halt THLTx */
+ etsec->regs[TSTAT].value |= 1 << (31 - ring_nbr);
+}
+
+static void fill_rx_bd(eTSEC *etsec,
+ eTSEC_rxtx_bd *bd,
+ const uint8_t **buf,
+ size_t *size)
+{
+ uint16_t to_write;
+ hwaddr bufptr = bd->bufptr +
+ ((hwaddr)(etsec->regs[TBDBPH].value & 0xF) << 32);
+ uint8_t padd[etsec->rx_padding];
+ uint8_t rem;
+
+ RING_DEBUG("eTSEC fill Rx buffer @ 0x%016" HWADDR_PRIx
+ " size:%zu(padding + crc:%u) + fcb:%u\n",
+ bufptr, *size, etsec->rx_padding, etsec->rx_fcb_size);
+
+ bd->length = 0;
+
+ /* This operation will only write FCB */
+ if (etsec->rx_fcb_size != 0) {
+
+ cpu_physical_memory_write(bufptr, etsec->rx_fcb, etsec->rx_fcb_size);
+
+ bufptr += etsec->rx_fcb_size;
+ bd->length += etsec->rx_fcb_size;
+ etsec->rx_fcb_size = 0;
+
+ }
+
+ /* We remove padding from the computation of to_write because it is not
+ * allocated in the buffer.
+ */
+ to_write = MIN(*size - etsec->rx_padding,
+ etsec->regs[MRBLR].value - etsec->rx_fcb_size);
+
+ /* This operation can only write packet data and no padding */
+ if (to_write > 0) {
+ cpu_physical_memory_write(bufptr, *buf, to_write);
+
+ *buf += to_write;
+ bufptr += to_write;
+ *size -= to_write;
+
+ bd->flags &= ~BD_RX_EMPTY;
+ bd->length += to_write;
+ }
+
+ if (*size == etsec->rx_padding) {
+ /* The remaining bytes are only for padding which is not actually
+ * allocated in the data buffer.
+ */
+
+ rem = MIN(etsec->regs[MRBLR].value - bd->length, etsec->rx_padding);
+
+ if (rem > 0) {
+ memset(padd, 0x0, sizeof(padd));
+ etsec->rx_padding -= rem;
+ *size -= rem;
+ bd->length += rem;
+ cpu_physical_memory_write(bufptr, padd, rem);
+ }
+ }
+}
+
+static void rx_init_frame(eTSEC *etsec, const uint8_t *buf, size_t size)
+{
+ uint32_t fcb_size = 0;
+ uint8_t prsdep = (etsec->regs[RCTRL].value >> RCTRL_PRSDEP_OFFSET)
+ & RCTRL_PRSDEP_MASK;
+
+ if (prsdep != 0) {
+ /* Prepend FCB (FCB size + RCTRL[PAL]) */
+ fcb_size = 8 + ((etsec->regs[RCTRL].value >> 16) & 0x1F);
+
+ etsec->rx_fcb_size = fcb_size;
+
+ /* TODO: fill_FCB(etsec); */
+ memset(etsec->rx_fcb, 0x0, sizeof(etsec->rx_fcb));
+
+ } else {
+ etsec->rx_fcb_size = 0;
+ }
+
+ if (etsec->rx_buffer != NULL) {
+ g_free(etsec->rx_buffer);
+ }
+
+ /* Do not copy the frame for now */
+ etsec->rx_buffer = (uint8_t *)buf;
+ etsec->rx_buffer_len = size;
+
+ /* CRC padding (We don't have to compute the CRC) */
+ etsec->rx_padding = 4;
+
+ etsec->rx_first_in_frame = 1;
+ etsec->rx_remaining_data = etsec->rx_buffer_len;
+ RING_DEBUG("%s: rx_buffer_len:%u rx_padding+crc:%u\n", __func__,
+ etsec->rx_buffer_len, etsec->rx_padding);
+}
+
+void etsec_rx_ring_write(eTSEC *etsec, const uint8_t *buf, size_t size)
+{
+ int ring_nbr = 0; /* Always use ring0 (no filer) */
+
+ if (etsec->rx_buffer_len != 0) {
+ RING_DEBUG("%s: We can't receive now,"
+ " a buffer is already in the pipe\n", __func__);
+ return;
+ }
+
+ if (etsec->regs[RSTAT].value & 1 << (23 - ring_nbr)) {
+ RING_DEBUG("%s: The ring is halted\n", __func__);
+ return;
+ }
+
+ if (etsec->regs[DMACTRL].value & DMACTRL_GRS) {
+ RING_DEBUG("%s: Graceful receive stop\n", __func__);
+ return;
+ }
+
+ if (!(etsec->regs[MACCFG1].value & MACCFG1_RX_EN)) {
+ RING_DEBUG("%s: MAC Receive not enabled\n", __func__);
+ return;
+ }
+
+ if ((etsec->regs[RCTRL].value & RCTRL_RSF) && (size < 60)) {
+ /* CRC is not in the packet yet, so short frame is below 60 bytes */
+ RING_DEBUG("%s: Drop short frame\n", __func__);
+ return;
+ }
+
+ rx_init_frame(etsec, buf, size);
+
+ etsec_walk_rx_ring(etsec, ring_nbr);
+}
+
+void etsec_walk_rx_ring(eTSEC *etsec, int ring_nbr)
+{
+ hwaddr ring_base = 0;
+ hwaddr bd_addr = 0;
+ hwaddr start_bd_addr = 0;
+ eTSEC_rxtx_bd bd;
+ uint16_t bd_flags;
+ size_t remaining_data;
+ const uint8_t *buf;
+ uint8_t *tmp_buf;
+ size_t size;
+
+ if (etsec->rx_buffer_len == 0) {
+ /* No frame to send */
+ RING_DEBUG("No frame to send\n");
+ return;
+ }
+
+ remaining_data = etsec->rx_remaining_data + etsec->rx_padding;
+ buf = etsec->rx_buffer
+ + (etsec->rx_buffer_len - etsec->rx_remaining_data);
+ size = etsec->rx_buffer_len + etsec->rx_padding;
+
+ ring_base = (hwaddr)(etsec->regs[RBASEH].value & 0xF) << 32;
+ ring_base += etsec->regs[RBASE0 + ring_nbr].value & ~0x7;
+ start_bd_addr = bd_addr = etsec->regs[RBPTR0 + ring_nbr].value & ~0x7;
+
+ do {
+ read_buffer_descriptor(etsec, bd_addr, &bd);
+
+#ifdef DEBUG_BD
+ print_bd(bd,
+ eTSEC_RECEIVE,
+ (bd_addr - ring_base) / sizeof(eTSEC_rxtx_bd));
+
+#endif /* DEBUG_BD */
+
+ /* Save flags before BD update */
+ bd_flags = bd.flags;
+
+ if (bd_flags & BD_RX_EMPTY) {
+ fill_rx_bd(etsec, &bd, &buf, &remaining_data);
+
+ if (etsec->rx_first_in_frame) {
+ bd.flags |= BD_RX_FIRST;
+ etsec->rx_first_in_frame = 0;
+ etsec->rx_first_bd = bd;
+ }
+
+ /* Last in frame */
+ if (remaining_data == 0) {
+
+ /* Clear flags */
+
+ bd.flags &= ~0x7ff;
+
+ bd.flags |= BD_LAST;
+
+ /* NOTE: non-octet aligned frame is impossible in qemu */
+
+ if (size >= etsec->regs[MAXFRM].value) {
+ /* frame length violation */
+ qemu_log("%s frame length violation: size:%zu MAXFRM:%d\n",
+ __func__, size, etsec->regs[MAXFRM].value);
+
+ bd.flags |= BD_RX_LG;
+ }
+
+ if (size < 64) {
+ /* Short frame */
+ bd.flags |= BD_RX_SH;
+ }
+
+ /* TODO: Broadcast and Multicast */
+
+ if (bd.flags | BD_INTERRUPT) {
+ /* Set RXFx */
+ etsec->regs[RSTAT].value |= 1 << (7 - ring_nbr);
+
+ /* Set IEVENT */
+ ievent_set(etsec, IEVENT_RXF);
+ }
+
+ } else {
+ if (bd.flags | BD_INTERRUPT) {
+ /* Set IEVENT */
+ ievent_set(etsec, IEVENT_RXB);
+ }
+ }
+
+ /* Write back BD after update */
+ write_buffer_descriptor(etsec, bd_addr, &bd);
+ }
+
+ /* Wrap or next BD */
+ if (bd_flags & BD_WRAP) {
+ bd_addr = ring_base;
+ } else {
+ bd_addr += sizeof(eTSEC_rxtx_bd);
+ }
+ } while (remaining_data != 0
+ && (bd_flags & BD_RX_EMPTY)
+ && bd_addr != start_bd_addr);
+
+ /* Reset ring ptr */
+ etsec->regs[RBPTR0 + ring_nbr].value = bd_addr;
+
+ /* The frame is too large to fit in the Rx ring */
+ if (remaining_data > 0) {
+
+ /* Set RSTAT[QHLTx] */
+ etsec->regs[RSTAT].value |= 1 << (23 - ring_nbr);
+
+ /* Save remaining data to send the end of the frame when the ring will
+ * be restarted
+ */
+ etsec->rx_remaining_data = remaining_data;
+
+ /* Copy the frame */
+ tmp_buf = g_malloc(size);
+ memcpy(tmp_buf, etsec->rx_buffer, size);
+ etsec->rx_buffer = tmp_buf;
+
+ RING_DEBUG("no empty RxBD available any more\n");
+ } else {
+ etsec->rx_buffer_len = 0;
+ etsec->rx_buffer = NULL;
+ }
+
+ RING_DEBUG("eTSEC End of ring_write: remaining_data:%zu\n", remaining_data);
+}
diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c
index 1bd6f50aaa..f6fbcb56bf 100644
--- a/hw/net/spapr_llan.c
+++ b/hw/net/spapr_llan.c
@@ -405,6 +405,8 @@ static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
dev->rx_bufs++;
+ qemu_flush_queued_packets(qemu_get_queue(dev->nic));
+
DPRINTF("h_add_logical_lan_buffer(): Added buf ptr=%d rx_bufs=%d"
" bd=0x%016llx\n", dev->add_buf_ptr, dev->rx_bufs,
(unsigned long long)buf);
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index b37ce9d633..8a08752613 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -238,6 +238,7 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args,
the first node as boot node and be happy */
for (i = smp_cpus - 1; i >= 0; i--) {
CPUState *cpu;
+ PowerPCCPU *pcpu;
char cpu_name[128];
uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20);
@@ -246,14 +247,16 @@ static int ppce500_load_device_tree(QEMUMachineInitArgs *args,
continue;
}
env = cpu->env_ptr;
+ pcpu = POWERPC_CPU(cpu);
snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x",
- cpu->cpu_index);
+ ppc_get_vcpu_dt_id(pcpu));
qemu_fdt_add_subnode(fdt, cpu_name);
qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
- qemu_fdt_setprop_cell(fdt, cpu_name, "reg", cpu->cpu_index);
+ qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
+ ppc_get_vcpu_dt_id(pcpu));
qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size",
env->dcache_line_size);
qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size",
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index 114be64480..0e82719b69 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -26,6 +26,7 @@
#include "hw/ppc/ppc_e500.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
+#include "sysemu/cpus.h"
#include "hw/timer/m48t59.h"
#include "qemu/log.h"
#include "hw/loader.h"
@@ -1362,3 +1363,24 @@ int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
return 0;
}
+
+/* CPU device-tree ID helpers */
+int ppc_get_vcpu_dt_id(PowerPCCPU *cpu)
+{
+ return cpu->cpu_dt_id;
+}
+
+PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id)
+{
+ CPUState *cs;
+
+ CPU_FOREACH(cs) {
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+
+ if (cpu->cpu_dt_id == cpu_dt_id) {
+ return cpu;
+ }
+ }
+
+ return NULL;
+}
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 93d02c1e50..bf46c380ec 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -49,6 +49,7 @@
#include "exec/address-spaces.h"
#include "hw/usb.h"
#include "qemu/config-file.h"
+#include "qemu/error-report.h"
#include <libfdt.h>
@@ -206,19 +207,20 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr)
CPU_FOREACH(cpu) {
DeviceClass *dc = DEVICE_GET_CLASS(cpu);
+ int index = ppc_get_vcpu_dt_id(POWERPC_CPU(cpu));
uint32_t associativity[] = {cpu_to_be32(0x5),
cpu_to_be32(0x0),
cpu_to_be32(0x0),
cpu_to_be32(0x0),
cpu_to_be32(cpu->numa_node),
- cpu_to_be32(cpu->cpu_index)};
+ cpu_to_be32(index)};
- if ((cpu->cpu_index % smt) != 0) {
+ if ((index % smt) != 0) {
continue;
}
snprintf(cpu_model, 32, "/cpus/%s@%x", dc->fw_name,
- cpu->cpu_index);
+ index);
offset = fdt_path_offset(fdt, cpu_model);
if (offset < 0) {
@@ -367,7 +369,7 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
CPUPPCState *env = &cpu->env;
DeviceClass *dc = DEVICE_GET_CLASS(cs);
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
- int index = cs->cpu_index;
+ int index = ppc_get_vcpu_dt_id(cpu);
uint32_t servers_prop[smp_threads];
uint32_t gservers_prop[smp_threads * 2];
char *nodename;
@@ -685,6 +687,7 @@ static void spapr_reset_htab(sPAPREnvironment *spapr)
if (shift > 0) {
/* Kernel handles htab, we don't need to allocate one */
spapr->htab_shift = shift;
+ kvmppc_kern_htab = true;
} else {
if (!spapr->htab) {
/* Allocate an htab if we don't yet have one */
@@ -740,8 +743,21 @@ static void spapr_cpu_reset(void *opaque)
env->spr[SPR_HIOR] = 0;
env->external_htab = (uint8_t *)spapr->htab;
+ if (kvm_enabled() && !env->external_htab) {
+ /*
+ * HV KVM, set external_htab to 1 so our ppc_hash64_load_hpte*
+ * functions do the right thing.
+ */
+ env->external_htab = (void *)1;
+ }
env->htab_base = -1;
- env->htab_mask = HTAB_SIZE(spapr) - 1;
+ /*
+ * htab_mask is the mask used to normalize hash value to PTEG index.
+ * htab_shift is log2 of hash table size.
+ * We have 8 hpte per group, and each hpte is 16 bytes.
+ * ie have 128 bytes per hpte entry.
+ */
+ env->htab_mask = (1ULL << ((spapr)->htab_shift - 7)) - 1;
env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab |
(spapr->htab_shift - 18);
}
@@ -1305,20 +1321,15 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0);
- if (kernel_size < 0) {
+ if (kernel_size == ELF_LOAD_WRONG_ENDIAN) {
kernel_size = load_elf(kernel_filename,
translate_kernel_address, NULL,
NULL, &lowaddr, NULL, 0, ELF_MACHINE, 0);
kernel_le = kernel_size > 0;
}
if (kernel_size < 0) {
- kernel_size = load_image_targphys(kernel_filename,
- KERNEL_LOAD_ADDR,
- load_limit - KERNEL_LOAD_ADDR);
- }
- if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- kernel_filename);
+ fprintf(stderr, "qemu: error loading %s: %s\n",
+ kernel_filename, load_elf_strerror(kernel_size));
exit(1);
}
@@ -1366,6 +1377,24 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
assert(spapr->fdt_skel != NULL);
}
+static int spapr_kvm_type(const char *vm_type)
+{
+ if (!vm_type) {
+ return 0;
+ }
+
+ if (!strcmp(vm_type, "HV")) {
+ return 1;
+ }
+
+ if (!strcmp(vm_type, "PR")) {
+ return 2;
+ }
+
+ error_report("Unknown kvm-type specified '%s'", vm_type);
+ exit(1);
+}
+
static QEMUMachine spapr_machine = {
.name = "pseries",
.desc = "pSeries Logical Partition (PAPR compliant)",
@@ -1376,6 +1405,7 @@ static QEMUMachine spapr_machine = {
.max_cpus = MAX_CPUS,
.no_parallel = 1,
.default_boot_order = NULL,
+ .kvm_type = spapr_kvm_type,
};
static void spapr_machine_init(void)
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 3ffcc65f03..d918780746 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -40,6 +40,17 @@ static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
return rb;
}
+static inline bool valid_pte_index(CPUPPCState *env, target_ulong pte_index)
+{
+ /*
+ * hash value/pteg group index is normalized by htab_mask
+ */
+ if (((pte_index & ~7ULL) / HPTES_PER_GROUP) & ~env->htab_mask) {
+ return false;
+ }
+ return true;
+}
+
static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args)
{
@@ -50,8 +61,8 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong ptel = args[3];
target_ulong page_shift = 12;
target_ulong raddr;
- target_ulong i;
- hwaddr hpte;
+ target_ulong index;
+ uint64_t token;
/* only handle 4k and 16M pages for now */
if (pteh & HPTE64_V_LARGE) {
@@ -91,33 +102,37 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
pteh &= ~0x60ULL;
- if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+ if (!valid_pte_index(env, pte_index)) {
return H_PARAMETER;
}
+
+ index = 0;
if (likely((flags & H_EXACT) == 0)) {
pte_index &= ~7ULL;
- hpte = pte_index * HASH_PTE_SIZE_64;
- for (i = 0; ; ++i) {
- if (i == 8) {
+ token = ppc_hash64_start_access(cpu, pte_index);
+ do {
+ if (index == 8) {
+ ppc_hash64_stop_access(token);
return H_PTEG_FULL;
}
- if ((ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) == 0) {
+ if ((ppc_hash64_load_hpte0(env, token, index) & HPTE64_V_VALID) == 0) {
break;
}
- hpte += HASH_PTE_SIZE_64;
- }
+ } while (index++);
+ ppc_hash64_stop_access(token);
} else {
- i = 0;
- hpte = pte_index * HASH_PTE_SIZE_64;
- if (ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) {
+ token = ppc_hash64_start_access(cpu, pte_index);
+ if (ppc_hash64_load_hpte0(env, token, 0) & HPTE64_V_VALID) {
+ ppc_hash64_stop_access(token);
return H_PTEG_FULL;
}
+ ppc_hash64_stop_access(token);
}
- ppc_hash64_store_hpte1(env, hpte, ptel);
- /* eieio(); FIXME: need some sort of barrier for smp? */
- ppc_hash64_store_hpte0(env, hpte, pteh | HPTE64_V_HPTE_DIRTY);
- args[0] = pte_index + i;
+ ppc_hash64_store_hpte(env, pte_index + index,
+ pteh | HPTE64_V_HPTE_DIRTY, ptel);
+
+ args[0] = pte_index + index;
return H_SUCCESS;
}
@@ -133,17 +148,17 @@ static RemoveResult remove_hpte(CPUPPCState *env, target_ulong ptex,
target_ulong flags,
target_ulong *vp, target_ulong *rp)
{
- hwaddr hpte;
+ uint64_t token;
target_ulong v, r, rb;
- if ((ptex * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+ if (!valid_pte_index(env, ptex)) {
return REMOVE_PARM;
}
- hpte = ptex * HASH_PTE_SIZE_64;
-
- v = ppc_hash64_load_hpte0(env, hpte);
- r = ppc_hash64_load_hpte1(env, hpte);
+ token = ppc_hash64_start_access(ppc_env_get_cpu(env), ptex);
+ v = ppc_hash64_load_hpte0(env, token, 0);
+ r = ppc_hash64_load_hpte1(env, token, 0);
+ ppc_hash64_stop_access(token);
if ((v & HPTE64_V_VALID) == 0 ||
((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
@@ -152,7 +167,7 @@ static RemoveResult remove_hpte(CPUPPCState *env, target_ulong ptex,
}
*vp = v;
*rp = r;
- ppc_hash64_store_hpte0(env, hpte, HPTE64_V_HPTE_DIRTY);
+ ppc_hash64_store_hpte(env, ptex, HPTE64_V_HPTE_DIRTY, 0);
rb = compute_tlbie_rb(v, r, ptex);
ppc_tlb_invalidate_one(env, rb);
return REMOVE_SUCCESS;
@@ -259,17 +274,17 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong flags = args[0];
target_ulong pte_index = args[1];
target_ulong avpn = args[2];
- hwaddr hpte;
+ uint64_t token;
target_ulong v, r, rb;
- if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+ if (!valid_pte_index(env, pte_index)) {
return H_PARAMETER;
}
- hpte = pte_index * HASH_PTE_SIZE_64;
-
- v = ppc_hash64_load_hpte0(env, hpte);
- r = ppc_hash64_load_hpte1(env, hpte);
+ token = ppc_hash64_start_access(cpu, pte_index);
+ v = ppc_hash64_load_hpte0(env, token, 0);
+ r = ppc_hash64_load_hpte1(env, token, 0);
+ ppc_hash64_stop_access(token);
if ((v & HPTE64_V_VALID) == 0 ||
((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
@@ -282,11 +297,11 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr,
r |= (flags << 48) & HPTE64_R_KEY_HI;
r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
rb = compute_tlbie_rb(v, r, pte_index);
- ppc_hash64_store_hpte0(env, hpte, (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY);
+ ppc_hash64_store_hpte(env, pte_index,
+ (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0);
ppc_tlb_invalidate_one(env, rb);
- ppc_hash64_store_hpte1(env, hpte, r);
/* Don't need a memory barrier, due to qemu's global lock */
- ppc_hash64_store_hpte0(env, hpte, v | HPTE64_V_HPTE_DIRTY);
+ ppc_hash64_store_hpte(env, pte_index, v | HPTE64_V_HPTE_DIRTY, r);
return H_SUCCESS;
}
@@ -299,7 +314,7 @@ static target_ulong h_read(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint8_t *hpte;
int i, ridx, n_entries = 1;
- if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+ if (!valid_pte_index(env, pte_index)) {
return H_PARAMETER;
}
@@ -467,13 +482,13 @@ static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong vpa = args[2];
target_ulong ret = H_PARAMETER;
CPUPPCState *tenv;
- CPUState *tcpu;
+ PowerPCCPU *tcpu;
- tcpu = qemu_get_cpu(procno);
+ tcpu = ppc_get_vcpu_by_dt_id(procno);
if (!tcpu) {
return H_PARAMETER;
}
- tenv = tcpu->env_ptr;
+ tenv = &tcpu->env;
switch (flags) {
case FLAGS_REGISTER_VPA:
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index ef45f4f0cc..d9fe946818 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -243,6 +243,42 @@ static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
return ret;
}
+static target_ulong get_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
+ target_ulong *tce)
+{
+ if (ioba >= tcet->window_size) {
+ hcall_dprintf("spapr_iommu_get_tce on out-of-bounds IOBA 0x"
+ TARGET_FMT_lx "\n", ioba);
+ return H_PARAMETER;
+ }
+
+ *tce = tcet->table[ioba >> SPAPR_TCE_PAGE_SHIFT];
+
+ return H_SUCCESS;
+}
+
+static target_ulong h_get_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ target_ulong liobn = args[0];
+ target_ulong ioba = args[1];
+ target_ulong tce = 0;
+ target_ulong ret = H_PARAMETER;
+ sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
+
+ ioba &= ~(SPAPR_TCE_PAGE_SIZE - 1);
+
+ if (tcet) {
+ ret = get_tce_emu(tcet, ioba, &tce);
+ if (!ret) {
+ args[0] = tce;
+ }
+ }
+ trace_spapr_iommu_get(liobn, ioba, ret, tce);
+
+ return ret;
+}
+
int spapr_dma_dt(void *fdt, int node_off, const char *propname,
uint32_t liobn, uint64_t window, uint32_t size)
{
@@ -295,6 +331,7 @@ static void spapr_tce_table_class_init(ObjectClass *klass, void *data)
/* hcall-tce */
spapr_register_hypercall(H_PUT_TCE, h_put_tce);
+ spapr_register_hypercall(H_GET_TCE, h_get_tce);
}
static TypeInfo spapr_tce_table_info = {
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 4c7c3aec12..cea9469872 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -469,6 +469,8 @@ static const MemoryRegionOps spapr_msi_ops = {
void spapr_pci_msi_init(sPAPREnvironment *spapr, hwaddr addr)
{
+ uint64_t window_size = 4096;
+
/*
* As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
* we need to allocate some memory to catch those writes coming
@@ -476,10 +478,19 @@ void spapr_pci_msi_init(sPAPREnvironment *spapr, hwaddr addr)
* As MSIMessage:addr is going to be the same and MSIMessage:data
* is going to be a VIRQ number, 4 bytes of the MSI MR will only
* be used.
+ *
+ * For KVM we want to ensure that this memory is a full page so that
+ * our memory slot is of page size granularity.
*/
+#ifdef CONFIG_KVM
+ if (kvm_enabled()) {
+ window_size = getpagesize();
+ }
+#endif
+
spapr->msi_win_addr = addr;
memory_region_init_io(&spapr->msiwindow, NULL, &spapr_msi_ops, spapr,
- "msi", getpagesize());
+ "msi", window_size);
memory_region_add_subregion(get_system_memory(), spapr->msi_win_addr,
&spapr->msiwindow);
}
@@ -728,6 +739,8 @@ static void spapr_phb_class_init(ObjectClass *klass, void *data)
dc->props = spapr_phb_properties;
dc->reset = spapr_phb_reset;
dc->vmsd = &vmstate_spapr_pci;
+ set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+ dc->cannot_instantiate_with_device_add_yet = false;
}
static const TypeInfo spapr_phb_info = {
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index 1cb276de05..73860d0486 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -131,7 +131,7 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_,
uint32_t nret, target_ulong rets)
{
target_ulong id;
- CPUState *cpu;
+ PowerPCCPU *cpu;
if (nargs != 1 || nret != 2) {
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
@@ -139,9 +139,9 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_,
}
id = rtas_ld(args, 0);
- cpu = qemu_get_cpu(id);
+ cpu = ppc_get_vcpu_by_dt_id(id);
if (cpu != NULL) {
- if (cpu->halted) {
+ if (CPU(cpu)->halted) {
rtas_st(rets, 1, 0);
} else {
rtas_st(rets, 1, 2);
@@ -161,7 +161,7 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr,
uint32_t nret, target_ulong rets)
{
target_ulong id, start, r3;
- CPUState *cs;
+ PowerPCCPU *cpu;
if (nargs != 3 || nret != 1) {
rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
@@ -172,9 +172,9 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr,
start = rtas_ld(args, 1);
r3 = rtas_ld(args, 2);
- cs = qemu_get_cpu(id);
- if (cs != NULL) {
- PowerPCCPU *cpu = POWERPC_CPU(cs);
+ cpu = ppc_get_vcpu_by_dt_id(id);
+ if (cpu != NULL) {
+ CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
if (!cs->halted) {
diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c
index 85a0e537b9..ce8ea91e8b 100644
--- a/hw/ppc/virtex_ml507.c
+++ b/hw/ppc/virtex_ml507.c
@@ -174,6 +174,19 @@ static int xilinx_load_device_tree(hwaddr addr,
if (!fdt) {
return 0;
}
+
+ r = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
+ initrd_base);
+ if (r < 0) {
+ error_report("couldn't set /chosen/linux,initrd-start");
+ }
+
+ r = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
+ (initrd_base + initrd_size));
+ if (r < 0) {
+ error_report("couldn't set /chosen/linux,initrd-end");
+ }
+
r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline);
if (r < 0)
fprintf(stderr, "couldn't set /chosen/bootargs\n");
@@ -187,6 +200,8 @@ static void virtex_init(QEMUMachineInitArgs *args)
const char *cpu_model = args->cpu_model;
const char *kernel_filename = args->kernel_filename;
const char *kernel_cmdline = args->kernel_cmdline;
+ hwaddr initrd_base = 0;
+ int initrd_size = 0;
MemoryRegion *address_space_mem = get_system_memory();
DeviceState *dev;
PowerPCCPU *cpu;
@@ -259,10 +274,27 @@ static void virtex_init(QEMUMachineInitArgs *args)
boot_info.ima_size = kernel_size;
+ /* Load initrd. */
+ if (args->initrd_filename) {
+ initrd_base = high = ROUND_UP(high, 4);
+ initrd_size = load_image_targphys(args->initrd_filename,
+ high, ram_size - high);
+
+ if (initrd_size < 0) {
+ error_report("couldn't load ram disk '%s'",
+ args->initrd_filename);
+ exit(1);
+ }
+ high = ROUND_UP(high + initrd_size, 4);
+ }
+
/* Provide a device-tree. */
boot_info.fdt = high + (8192 * 2);
boot_info.fdt &= ~8191;
- xilinx_load_device_tree(boot_info.fdt, ram_size, 0, 0, kernel_cmdline);
+
+ xilinx_load_device_tree(boot_info.fdt, ram_size,
+ initrd_base, initrd_size,
+ kernel_cmdline);
}
env->load_info = &boot_info;
}
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index 75b04b45af..7074d2b3d5 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -116,6 +116,15 @@ void css_conditional_io_interrupt(SubchDev *sch)
}
}
+void css_adapter_interrupt(uint8_t isc)
+{
+ S390CPU *cpu = s390_cpu_addr2state(0);
+ uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI;
+
+ trace_css_adapter_interrupt(isc);
+ s390_io_interrupt(cpu, 0, 0, 0, io_int_word);
+}
+
static void sch_handle_clear_func(SubchDev *sch)
{
PMCW *p = &sch->curr_status.pmcw;
@@ -1259,6 +1268,7 @@ void css_reset_sch(SubchDev *sch)
sch->channel_prog = 0x0;
sch->last_cmd_valid = false;
sch->orb = NULL;
+ sch->thinint_active = false;
}
void css_reset(void)
diff --git a/hw/s390x/css.h b/hw/s390x/css.h
index b536ab5957..e9b440540d 100644
--- a/hw/s390x/css.h
+++ b/hw/s390x/css.h
@@ -77,6 +77,7 @@ struct SubchDev {
CCW1 last_cmd;
bool last_cmd_valid;
ORB *orb;
+ bool thinint_active;
/* transport-provided data: */
int (*ccw_cb) (SubchDev *, CCW1);
SenseId id;
@@ -97,4 +98,5 @@ void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid);
void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid,
int hotplugged, int add);
void css_generate_chp_crws(uint8_t cssid, uint8_t chpid);
+void css_adapter_interrupt(uint8_t isc);
#endif
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 04fb1a8e05..32d38a08f6 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -98,10 +98,10 @@ static int s390_ipl_init(SysBusDevice *dev)
uint64_t pentry = KERN_IMAGE_START;
kernel_size = load_elf(ipl->kernel, NULL, NULL, &pentry, NULL,
NULL, 1, ELF_MACHINE, 0);
- if (kernel_size == -1) {
+ if (kernel_size < 0) {
kernel_size = load_image_targphys(ipl->kernel, 0, ram_size);
}
- if (kernel_size == -1) {
+ if (kernel_size < 0) {
fprintf(stderr, "could not load kernel '%s'\n", ipl->kernel);
return -1;
}
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index f6e0e3e4ae..a01801e342 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -1,7 +1,7 @@
/*
* virtio ccw target implementation
*
- * Copyright 2012 IBM Corp.
+ * Copyright 2012,2014 IBM Corp.
* Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
@@ -188,6 +188,13 @@ typedef struct VirtioFeatDesc {
uint8_t index;
} QEMU_PACKED VirtioFeatDesc;
+typedef struct VirtioThinintInfo {
+ hwaddr summary_indicator;
+ hwaddr device_indicator;
+ uint64_t ind_bit;
+ uint8_t isc;
+} QEMU_PACKED VirtioThinintInfo;
+
/* Specify where the virtqueues for the subchannel are in guest memory. */
static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align,
uint16_t index, uint16_t num)
@@ -237,6 +244,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
bool check_len;
int len;
hwaddr hw_len;
+ VirtioThinintInfo *thinint;
if (!dev) {
return -EINVAL;
@@ -428,6 +436,11 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
ret = -EINVAL;
break;
}
+ if (sch->thinint_active) {
+ /* Trigger a command reject. */
+ ret = -ENOSYS;
+ break;
+ }
if (!ccw.cda) {
ret = -EFAULT;
} else {
@@ -480,6 +493,42 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
ret = 0;
}
break;
+ case CCW_CMD_SET_IND_ADAPTER:
+ if (check_len) {
+ if (ccw.count != sizeof(*thinint)) {
+ ret = -EINVAL;
+ break;
+ }
+ } else if (ccw.count < sizeof(*thinint)) {
+ /* Can't execute command. */
+ ret = -EINVAL;
+ break;
+ }
+ len = sizeof(*thinint);
+ hw_len = len;
+ if (!ccw.cda) {
+ ret = -EFAULT;
+ } else if (dev->indicators && !sch->thinint_active) {
+ /* Trigger a command reject. */
+ ret = -ENOSYS;
+ } else {
+ thinint = cpu_physical_memory_map(ccw.cda, &hw_len, 0);
+ if (!thinint) {
+ ret = -EFAULT;
+ } else {
+ len = hw_len;
+ dev->summary_indicator = thinint->summary_indicator;
+ dev->indicators = thinint->device_indicator;
+ dev->thinint_isc = thinint->isc;
+ dev->ind_bit = thinint->ind_bit;
+ cpu_physical_memory_unmap(thinint, hw_len, 0, hw_len);
+ sch->thinint_active = ((dev->indicators != 0) &&
+ (dev->summary_indicator != 0));
+ sch->curr_status.scsw.count = ccw.count - len;
+ ret = 0;
+ }
+ }
+ break;
default:
ret = -ENOSYS;
break;
@@ -511,6 +560,7 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
sch->channel_prog = 0x0;
sch->last_cmd_valid = false;
sch->orb = NULL;
+ sch->thinint_active = false;
/*
* Use a device number if provided. Otherwise, fall back to subchannel
* number.
@@ -858,6 +908,28 @@ static inline VirtioCcwDevice *to_virtio_ccw_dev_fast(DeviceState *d)
return container_of(d, VirtioCcwDevice, parent_obj);
}
+static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc,
+ uint8_t to_be_set)
+{
+ uint8_t ind_old, ind_new;
+ hwaddr len = 1;
+ uint8_t *ind_addr;
+
+ ind_addr = cpu_physical_memory_map(ind_loc, &len, 1);
+ if (!ind_addr) {
+ error_report("%s(%x.%x.%04x): unable to access indicator",
+ __func__, sch->cssid, sch->ssid, sch->schid);
+ return -1;
+ }
+ do {
+ ind_old = *ind_addr;
+ ind_new = ind_old | to_be_set;
+ } while (atomic_cmpxchg(ind_addr, ind_old, ind_new) != ind_old);
+ cpu_physical_memory_unmap(ind_addr, len, 1, len);
+
+ return ind_old;
+}
+
static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
{
VirtioCcwDevice *dev = to_virtio_ccw_dev_fast(d);
@@ -872,9 +944,26 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
if (!dev->indicators) {
return;
}
- indicators = ldq_phys(&address_space_memory, dev->indicators);
- indicators |= 1ULL << vector;
- stq_phys(&address_space_memory, dev->indicators, indicators);
+ if (sch->thinint_active) {
+ /*
+ * In the adapter interrupt case, indicators points to a
+ * memory area that may be (way) larger than 64 bit and
+ * ind_bit indicates the start of the indicators in a big
+ * endian notation.
+ */
+ virtio_set_ind_atomic(sch, dev->indicators +
+ (dev->ind_bit + vector) / 8,
+ 0x80 >> ((dev->ind_bit + vector) % 8));
+ if (!virtio_set_ind_atomic(sch, dev->summary_indicator,
+ 0x01)) {
+ css_adapter_interrupt(dev->thinint_isc);
+ }
+ } else {
+ indicators = ldq_phys(&address_space_memory, dev->indicators);
+ indicators |= 1ULL << vector;
+ stq_phys(&address_space_memory, dev->indicators, indicators);
+ css_conditional_io_interrupt(sch);
+ }
} else {
if (!dev->indicators2) {
return;
@@ -883,10 +972,8 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
indicators = ldq_phys(&address_space_memory, dev->indicators2);
indicators |= 1ULL << vector;
stq_phys(&address_space_memory, dev->indicators2, indicators);
+ css_conditional_io_interrupt(sch);
}
-
- css_conditional_io_interrupt(sch);
-
}
static unsigned virtio_ccw_get_features(DeviceState *d)
@@ -907,6 +994,7 @@ static void virtio_ccw_reset(DeviceState *d)
css_reset_sch(dev->sch);
dev->indicators = 0;
dev->indicators2 = 0;
+ dev->summary_indicator = 0;
}
static void virtio_ccw_vmstate_change(DeviceState *d, bool running)
diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h
index 00932c746d..4393e44814 100644
--- a/hw/s390x/virtio-ccw.h
+++ b/hw/s390x/virtio-ccw.h
@@ -38,6 +38,7 @@
#define CCW_CMD_SET_IND 0x43
#define CCW_CMD_SET_CONF_IND 0x53
#define CCW_CMD_READ_VQ_CONF 0x32
+#define CCW_CMD_SET_IND_ADAPTER 0x73
#define TYPE_VIRTIO_CCW_DEVICE "virtio-ccw-device"
#define VIRTIO_CCW_DEVICE(obj) \
@@ -83,9 +84,12 @@ struct VirtioCcwDevice {
bool ioeventfd_started;
bool ioeventfd_disabled;
uint32_t flags;
+ uint8_t thinint_isc;
/* Guest provided values: */
hwaddr indicators;
hwaddr indicators2;
+ hwaddr summary_indicator;
+ uint64_t ind_bit;
};
/* virtual css bus type */
diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c
index e8bca390dd..b3835c821d 100644
--- a/hw/scsi/spapr_vscsi.c
+++ b/hw/scsi/spapr_vscsi.c
@@ -62,6 +62,8 @@
#define SRP_RSP_SENSE_DATA_LEN 18
+#define SRP_REPORT_LUNS_WLUN 0xc10100000000000ULL
+
typedef union vscsi_crq {
struct viosrp_crq s;
uint8_t raw[16];
@@ -719,12 +721,70 @@ static void vscsi_inquiry_no_target(VSCSIState *s, vscsi_req *req)
}
}
+static void vscsi_report_luns(VSCSIState *s, vscsi_req *req)
+{
+ BusChild *kid;
+ int i, len, n, rc;
+ uint8_t *resp_data;
+ bool found_lun0;
+
+ n = 0;
+ found_lun0 = false;
+ QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
+ SCSIDevice *dev = SCSI_DEVICE(kid->child);
+
+ n += 8;
+ if (dev->channel == 0 && dev->id == 0 && dev->lun == 0) {
+ found_lun0 = true;
+ }
+ }
+ if (!found_lun0) {
+ n += 8;
+ }
+ len = n+8;
+
+ resp_data = g_malloc0(len);
+ memset(resp_data, 0, len);
+ stl_be_p(resp_data, n);
+ i = found_lun0 ? 8 : 16;
+ QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
+ DeviceState *qdev = kid->child;
+ SCSIDevice *dev = SCSI_DEVICE(qdev);
+
+ if (dev->id == 0 && dev->channel == 0) {
+ resp_data[i] = 0; /* Use simple LUN for 0 (SAM5 4.7.7.1) */
+ } else {
+ resp_data[i] = (2 << 6); /* Otherwise LUN addressing (4.7.7.4) */
+ }
+ resp_data[i] |= dev->id;
+ resp_data[i+1] = (dev->channel << 5);
+ resp_data[i+1] |= dev->lun;
+ i += 8;
+ }
+
+ vscsi_preprocess_desc(req);
+ rc = vscsi_srp_transfer_data(s, req, 0, resp_data, len);
+ g_free(resp_data);
+ if (rc < 0) {
+ vscsi_makeup_sense(s, req, HARDWARE_ERROR, 0, 0);
+ vscsi_send_rsp(s, req, CHECK_CONDITION, 0, 0);
+ } else {
+ vscsi_send_rsp(s, req, 0, len - rc, 0);
+ }
+}
+
static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
{
union srp_iu *srp = &req->iu.srp;
SCSIDevice *sdev;
int n, lun;
+ if ((srp->cmd.lun == 0 || be64_to_cpu(srp->cmd.lun) == SRP_REPORT_LUNS_WLUN)
+ && srp->cmd.cdb[0] == REPORT_LUNS) {
+ vscsi_report_luns(s, req);
+ return 0;
+ }
+
sdev = vscsi_device_find(&s->bus, be64_to_cpu(srp->cmd.lun), &lun);
if (!sdev) {
DPRINTF("VSCSI: Command for lun %08" PRIx64 " with no drive\n",
diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c
index e05cbc131e..42913b6a5a 100644
--- a/hw/unicore32/puv3.c
+++ b/hw/unicore32/puv3.c
@@ -98,7 +98,7 @@ static void puv3_load_kernel(const char *kernel_filename)
}
/* cheat curses that we have a graphic console, only under ocd console */
- graphic_console_init(NULL, &no_ops, NULL);
+ graphic_console_init(NULL, 0, &no_ops, NULL);
}
static void puv3_init(QEMUMachineInitArgs *args)
diff --git a/include/hw/boards.h b/include/hw/boards.h
index 2151460f9e..c2096e6ba2 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -4,10 +4,9 @@
#define HW_BOARDS_H
#include "sysemu/blockdev.h"
+#include "sysemu/qemumachine.h"
#include "hw/qdev.h"
-typedef struct QEMUMachine QEMUMachine;
-
typedef struct QEMUMachineInitArgs {
const QEMUMachine *machine;
ram_addr_t ram_size;
@@ -24,6 +23,8 @@ typedef void QEMUMachineResetFunc(void);
typedef void QEMUMachineHotAddCPUFunc(const int64_t id, Error **errp);
+typedef int QEMUMachineGetKvmtypeFunc(const char *arg);
+
struct QEMUMachine {
const char *name;
const char *alias;
@@ -31,6 +32,7 @@ struct QEMUMachine {
QEMUMachineInitFunc *init;
QEMUMachineResetFunc *reset;
QEMUMachineHotAddCPUFunc *hot_add_cpu;
+ QEMUMachineGetKvmtypeFunc *kvm_type;
BlockInterfaceType block_default_type;
int max_cpus;
unsigned int no_serial:1,
diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h
index acc701e3a4..c6b5129bab 100644
--- a/include/hw/elf_ops.h
+++ b/include/hw/elf_ops.h
@@ -201,6 +201,7 @@ static int glue(load_elf, SZ)(const char *name, int fd,
uint64_t addr, low = (uint64_t)-1, high = 0;
uint8_t *data = NULL;
char label[128];
+ int ret = ELF_LOAD_FAILED;
if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
goto fail;
@@ -211,22 +212,30 @@ static int glue(load_elf, SZ)(const char *name, int fd,
switch (elf_machine) {
case EM_PPC64:
if (EM_PPC64 != ehdr.e_machine)
- if (EM_PPC != ehdr.e_machine)
+ if (EM_PPC != ehdr.e_machine) {
+ ret = ELF_LOAD_WRONG_ARCH;
goto fail;
+ }
break;
case EM_X86_64:
if (EM_X86_64 != ehdr.e_machine)
- if (EM_386 != ehdr.e_machine)
+ if (EM_386 != ehdr.e_machine) {
+ ret = ELF_LOAD_WRONG_ARCH;
goto fail;
+ }
break;
case EM_MICROBLAZE:
if (EM_MICROBLAZE != ehdr.e_machine)
- if (EM_MICROBLAZE_OLD != ehdr.e_machine)
+ if (EM_MICROBLAZE_OLD != ehdr.e_machine) {
+ ret = ELF_LOAD_WRONG_ARCH;
goto fail;
+ }
break;
default:
- if (elf_machine != ehdr.e_machine)
+ if (elf_machine != ehdr.e_machine) {
+ ret = ELF_LOAD_WRONG_ARCH;
goto fail;
+ }
}
if (pentry)
@@ -305,5 +314,5 @@ static int glue(load_elf, SZ)(const char *name, int fd,
fail:
g_free(data);
g_free(phdr);
- return -1;
+ return ret;
}
diff --git a/include/hw/loader.h b/include/hw/loader.h
index 91b01224a3..aaf08c377e 100644
--- a/include/hw/loader.h
+++ b/include/hw/loader.h
@@ -15,6 +15,12 @@ int get_image_size(const char *filename);
int load_image(const char *filename, uint8_t *addr); /* deprecated */
int load_image_targphys(const char *filename, hwaddr,
uint64_t max_sz);
+
+#define ELF_LOAD_FAILED -1
+#define ELF_LOAD_NOT_ELF -2
+#define ELF_LOAD_WRONG_ARCH -3
+#define ELF_LOAD_WRONG_ENDIAN -4
+const char *load_elf_strerror(int error);
int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
uint64_t *highaddr, int big_endian, int elf_machine,
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 276b336c09..1ed0691716 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -176,6 +176,8 @@ struct BusClass {
void (*reset)(BusState *bus);
/* maximum devices allowed on the bus, 0: no limit. */
int max_dev;
+ /* number of automatically allocated bus ids (e.g. ide.0) */
+ int automatic_ids;
};
typedef struct BusChild {
diff --git a/include/hw/xen/xen.h b/include/hw/xen/xen.h
index e1f88bf9cf..e1818213b2 100644
--- a/include/hw/xen/xen.h
+++ b/include/hw/xen/xen.h
@@ -10,6 +10,7 @@
#include "hw/irq.h"
#include "qemu-common.h"
+#include "sysemu/qemumachine.h"
/* xen-machine.c */
enum xen_mode {
@@ -36,7 +37,7 @@ void xen_cmos_set_s3_resume(void *opaque, int irq, int level);
qemu_irq *xen_interrupt_controller_init(void);
-int xen_init(void);
+int xen_init(QEMUMachine *machine);
int xen_hvm_init(MemoryRegion **ram_memory);
void xenstore_store_pv_console_info(int i, struct CharDriverState *chr);
diff --git a/include/qemu/host-utils.h b/include/qemu/host-utils.h
index 285c5fbab8..d4f21c947f 100644
--- a/include/qemu/host-utils.h
+++ b/include/qemu/host-utils.h
@@ -44,9 +44,37 @@ static inline void muls64(uint64_t *plow, uint64_t *phigh,
*plow = r;
*phigh = r >> 64;
}
+
+static inline int divu128(uint64_t *plow, uint64_t *phigh, uint64_t divisor)
+{
+ if (divisor == 0) {
+ return 1;
+ } else {
+ __uint128_t dividend = ((__uint128_t)*phigh << 64) | *plow;
+ __uint128_t result = dividend / divisor;
+ *plow = result;
+ *phigh = dividend % divisor;
+ return result > UINT64_MAX;
+ }
+}
+
+static inline int divs128(int64_t *plow, int64_t *phigh, int64_t divisor)
+{
+ if (divisor == 0) {
+ return 1;
+ } else {
+ __int128_t dividend = ((__int128_t)*phigh << 64) | *plow;
+ __int128_t result = dividend / divisor;
+ *plow = result;
+ *phigh = dividend % divisor;
+ return result != *plow;
+ }
+}
#else
void muls64(uint64_t *phigh, uint64_t *plow, int64_t a, int64_t b);
void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b);
+int divu128(uint64_t *plow, uint64_t *phigh, uint64_t divisor);
+int divs128(int64_t *plow, int64_t *phigh, int64_t divisor);
#endif
/**
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index a02d67cd5a..ed01998aa8 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -18,6 +18,7 @@
#include "config-host.h"
#include "qemu/queue.h"
#include "qom/cpu.h"
+#include "sysemu/qemumachine.h"
#ifdef CONFIG_KVM
#include <linux/kvm.h>
@@ -152,7 +153,7 @@ extern KVMState *kvm_state;
/* external API */
-int kvm_init(void);
+int kvm_init(QEMUMachine *machine);
int kvm_has_sync_mmu(void);
int kvm_has_vcpu_events(void);
diff --git a/include/sysemu/qemumachine.h b/include/sysemu/qemumachine.h
new file mode 100644
index 0000000000..4cefd56b67
--- /dev/null
+++ b/include/sysemu/qemumachine.h
@@ -0,0 +1,16 @@
+/*
+ * QEMU Machine typedef
+ *
+ * Copyright Alexander Graf <agraf@suse.de>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef QEMUMACHINE_H
+#define QEMUMACHINE_H
+
+typedef struct QEMUMachine QEMUMachine;
+
+#endif /* !QEMUMACHINE_H */
diff --git a/include/sysemu/qtest.h b/include/sysemu/qtest.h
index 28f4875112..e62281d4bf 100644
--- a/include/sysemu/qtest.h
+++ b/include/sysemu/qtest.h
@@ -16,6 +16,7 @@
#include "qemu-common.h"
#include "qapi/error.h"
+#include "sysemu/qemumachine.h"
extern bool qtest_allowed;
@@ -26,7 +27,7 @@ static inline bool qtest_enabled(void)
bool qtest_driver(void);
-int qtest_init_accel(void);
+int qtest_init_accel(QEMUMachine *machine);
void qtest_init(const char *qtest_chrdev, const char *qtest_log, Error **errp);
static inline int qtest_available(void)
diff --git a/include/ui/console.h b/include/ui/console.h
index 4156a876e1..08a38eab13 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -14,6 +14,8 @@
#define MOUSE_EVENT_LBUTTON 0x01
#define MOUSE_EVENT_RBUTTON 0x02
#define MOUSE_EVENT_MBUTTON 0x04
+#define MOUSE_EVENT_WHEELUP 0x08
+#define MOUSE_EVENT_WHEELDN 0x10
/* identical to the ps/2 keyboard bits */
#define QEMU_SCROLL_LOCK_LED (1 << 0)
@@ -44,17 +46,7 @@ void qemu_activate_mouse_event_handler(QEMUPutMouseEntry *entry);
QEMUPutLEDEntry *qemu_add_led_event_handler(QEMUPutLEDEvent *func, void *opaque);
void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry);
-void kbd_put_keycode(int keycode);
void kbd_put_ledstate(int ledstate);
-void kbd_mouse_event(int dx, int dy, int dz, int buttons_state);
-
-/* Does the current mouse generate absolute events */
-int kbd_mouse_is_absolute(void);
-void qemu_add_mouse_mode_change_notifier(Notifier *notify);
-void qemu_remove_mouse_mode_change_notifier(Notifier *notify);
-
-/* Of all the mice, is there one that generates absolute events */
-int kbd_mouse_has_absolute(void);
struct MouseTransformInfo {
/* Touchscreen resolution */
@@ -128,6 +120,14 @@ struct DisplaySurface {
struct PixelFormat pf;
};
+typedef struct QemuUIInfo {
+ /* geometry */
+ int xoff;
+ int yoff;
+ uint32_t width;
+ uint32_t height;
+} QemuUIInfo;
+
/* cursor data format is 32bit RGBA */
typedef struct QEMUCursor {
int width, height;
@@ -212,6 +212,8 @@ void update_displaychangelistener(DisplayChangeListener *dcl,
uint64_t interval);
void unregister_displaychangelistener(DisplayChangeListener *dcl);
+int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info);
+
void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h);
void dpy_gfx_replace_surface(QemuConsole *con,
DisplaySurface *surface);
@@ -274,9 +276,10 @@ typedef struct GraphicHwOps {
void (*gfx_update)(void *opaque);
void (*text_update)(void *opaque, console_ch_t *text);
void (*update_interval)(void *opaque, uint64_t interval);
+ int (*ui_info)(void *opaque, uint32_t head, QemuUIInfo *info);
} GraphicHwOps;
-QemuConsole *graphic_console_init(DeviceState *dev,
+QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
const GraphicHwOps *ops,
void *opaque);
@@ -285,10 +288,15 @@ void graphic_hw_invalidate(QemuConsole *con);
void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata);
QemuConsole *qemu_console_lookup_by_index(unsigned int index);
-QemuConsole *qemu_console_lookup_by_device(DeviceState *dev);
+QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head);
bool qemu_console_is_visible(QemuConsole *con);
bool qemu_console_is_graphic(QemuConsole *con);
bool qemu_console_is_fixedsize(QemuConsole *con);
+int qemu_console_get_index(QemuConsole *con);
+uint32_t qemu_console_get_head(QemuConsole *con);
+QemuUIInfo *qemu_console_get_ui_info(QemuConsole *con);
+int qemu_console_get_width(QemuConsole *con, int fallback);
+int qemu_console_get_height(QemuConsole *con, int fallback);
void text_consoles_set_display(DisplayState *ds);
void console_select(unsigned int index);
@@ -334,7 +342,6 @@ void curses_display_init(DisplayState *ds, int full_screen);
/* input.c */
int index_from_key(const char *key);
-int index_from_keycode(int code);
/* gtk.c */
void early_gtk_display_init(void);
diff --git a/include/ui/input.h b/include/ui/input.h
new file mode 100644
index 0000000000..4976f3da2c
--- /dev/null
+++ b/include/ui/input.h
@@ -0,0 +1,56 @@
+#ifndef INPUT_H
+#define INPUT_H
+
+#include "qapi-types.h"
+
+#define INPUT_EVENT_MASK_KEY (1<<INPUT_EVENT_KIND_KEY)
+#define INPUT_EVENT_MASK_BTN (1<<INPUT_EVENT_KIND_BTN)
+#define INPUT_EVENT_MASK_REL (1<<INPUT_EVENT_KIND_REL)
+#define INPUT_EVENT_MASK_ABS (1<<INPUT_EVENT_KIND_ABS)
+
+#define INPUT_EVENT_ABS_SIZE 0x8000
+
+typedef struct QemuInputHandler QemuInputHandler;
+typedef struct QemuInputHandlerState QemuInputHandlerState;
+
+typedef void (*QemuInputHandlerEvent)(DeviceState *dev, QemuConsole *src,
+ InputEvent *evt);
+typedef void (*QemuInputHandlerSync)(DeviceState *dev);
+
+struct QemuInputHandler {
+ const char *name;
+ uint32_t mask;
+ QemuInputHandlerEvent event;
+ QemuInputHandlerSync sync;
+};
+
+QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
+ QemuInputHandler *handler);
+void qemu_input_handler_activate(QemuInputHandlerState *s);
+void qemu_input_handler_unregister(QemuInputHandlerState *s);
+void qemu_input_event_send(QemuConsole *src, InputEvent *evt);
+void qemu_input_event_sync(void);
+
+InputEvent *qemu_input_event_new_key(KeyValue *key, bool down);
+void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down);
+void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down);
+void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down);
+
+InputEvent *qemu_input_event_new_btn(InputButton btn, bool down);
+void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down);
+void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map,
+ uint32_t button_old, uint32_t button_new);
+
+bool qemu_input_is_absolute(void);
+int qemu_input_scale_axis(int value, int size_in, int size_out);
+InputEvent *qemu_input_event_new_move(InputEventKind kind,
+ InputAxis axis, int value);
+void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value);
+void qemu_input_queue_abs(QemuConsole *src, InputAxis axis,
+ int value, int size);
+
+void qemu_input_check_mode_change(void);
+void qemu_add_mouse_mode_change_notifier(Notifier *notify);
+void qemu_remove_mouse_mode_change_notifier(Notifier *notify);
+
+#endif /* INPUT_H */
diff --git a/kvm-all.c b/kvm-all.c
index fd8157ad5e..87fe4821a6 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -36,6 +36,8 @@
#include "qemu/event_notifier.h"
#include "trace.h"
+#include "hw/boards.h"
+
/* This check must be after config-host.h is included */
#ifdef CONFIG_EVENTFD
#include <sys/eventfd.h>
@@ -1339,7 +1341,7 @@ static int kvm_max_vcpus(KVMState *s)
return (ret) ? ret : kvm_recommended_vcpus(s);
}
-int kvm_init(void)
+int kvm_init(QEMUMachine *machine)
{
static const char upgrade_note[] =
"Please upgrade to at least kernel 2.6.29 or recent kvm-kmod\n"
@@ -1356,7 +1358,8 @@ int kvm_init(void)
KVMState *s;
const KVMCapabilityInfo *missing_cap;
int ret;
- int i;
+ int i, type = 0;
+ const char *kvm_type;
s = g_malloc0(sizeof(KVMState));
@@ -1430,8 +1433,16 @@ int kvm_init(void)
nc++;
}
+ kvm_type = qemu_opt_get(qemu_get_machine_opts(), "kvm-type");
+ if (machine->kvm_type) {
+ type = machine->kvm_type(kvm_type);
+ } else if (kvm_type) {
+ fprintf(stderr, "Invalid argument kvm-type=%s\n", kvm_type);
+ goto err;
+ }
+
do {
- ret = kvm_ioctl(s, KVM_CREATE_VM, 0);
+ ret = kvm_ioctl(s, KVM_CREATE_VM, type);
} while (ret == -EINTR);
if (ret < 0) {
diff --git a/kvm-stub.c b/kvm-stub.c
index e979f76d07..4ef084e84a 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -14,6 +14,7 @@
#include "hw/hw.h"
#include "cpu.h"
#include "sysemu/kvm.h"
+#include "sysemu/qemumachine.h"
#ifndef CONFIG_USER_ONLY
#include "hw/pci/msi.h"
@@ -34,7 +35,7 @@ int kvm_init_vcpu(CPUState *cpu)
return -ENOSYS;
}
-int kvm_init(void)
+int kvm_init(QEMUMachine *machine)
{
return -ENOSYS;
}
diff --git a/linux-user/main.c b/linux-user/main.c
index 919297736c..be9491bc7d 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -1492,7 +1492,7 @@ static int do_store_exclusive(CPUPPCState *env)
{
target_ulong addr;
target_ulong page_addr;
- target_ulong val;
+ target_ulong val, val2 __attribute__((unused));
int flags;
int segv = 0;
@@ -1515,6 +1515,13 @@ static int do_store_exclusive(CPUPPCState *env)
case 4: segv = get_user_u32(val, addr); break;
#if defined(TARGET_PPC64)
case 8: segv = get_user_u64(val, addr); break;
+ case 16: {
+ segv = get_user_u64(val, addr);
+ if (!segv) {
+ segv = get_user_u64(val2, addr + 8);
+ }
+ break;
+ }
#endif
default: abort();
}
@@ -1526,6 +1533,15 @@ static int do_store_exclusive(CPUPPCState *env)
case 4: segv = put_user_u32(val, addr); break;
#if defined(TARGET_PPC64)
case 8: segv = put_user_u64(val, addr); break;
+ case 16: {
+ if (val2 == env->reserve_val2) {
+ segv = put_user_u64(val, addr);
+ if (!segv) {
+ segv = put_user_u64(val2, addr + 8);
+ }
+ }
+ break;
+ }
#endif
default: abort();
}
diff --git a/monitor.c b/monitor.c
index 3863d83466..342e83baea 100644
--- a/monitor.c
+++ b/monitor.c
@@ -39,6 +39,7 @@
#include "monitor/monitor.h"
#include "qemu/readline.h"
#include "ui/console.h"
+#include "ui/input.h"
#include "sysemu/blockdev.h"
#include "audio/audio.h"
#include "disas/disas.h"
@@ -1463,23 +1464,43 @@ static int mouse_button_state;
static void do_mouse_move(Monitor *mon, const QDict *qdict)
{
- int dx, dy, dz;
+ int dx, dy, dz, button;
const char *dx_str = qdict_get_str(qdict, "dx_str");
const char *dy_str = qdict_get_str(qdict, "dy_str");
const char *dz_str = qdict_get_try_str(qdict, "dz_str");
+
dx = strtol(dx_str, NULL, 0);
dy = strtol(dy_str, NULL, 0);
- dz = 0;
- if (dz_str)
+ qemu_input_queue_rel(NULL, INPUT_AXIS_X, dx);
+ qemu_input_queue_rel(NULL, INPUT_AXIS_Y, dy);
+
+ if (dz_str) {
dz = strtol(dz_str, NULL, 0);
- kbd_mouse_event(dx, dy, dz, mouse_button_state);
+ if (dz != 0) {
+ button = (dz > 0) ? INPUT_BUTTON_WHEEL_UP : INPUT_BUTTON_WHEEL_DOWN;
+ qemu_input_queue_btn(NULL, button, true);
+ qemu_input_event_sync();
+ qemu_input_queue_btn(NULL, button, false);
+ }
+ }
+ qemu_input_event_sync();
}
static void do_mouse_button(Monitor *mon, const QDict *qdict)
{
+ static uint32_t bmap[INPUT_BUTTON_MAX] = {
+ [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
+ [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
+ [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
+ };
int button_state = qdict_get_int(qdict, "button_state");
+
+ if (mouse_button_state == button_state) {
+ return;
+ }
+ qemu_input_update_buttons(NULL, bmap, mouse_button_state, button_state);
+ qemu_input_event_sync();
mouse_button_state = button_state;
- kbd_mouse_event(0, 0, 0, mouse_button_state);
}
static void do_ioport_read(Monitor *mon, const QDict *qdict)
diff --git a/qapi-schema.json b/qapi-schema.json
index 193e7e4d3f..6c381b7306 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -3555,9 +3555,12 @@
# This is used by the send-key command.
#
# Since: 1.3.0
+#
+# 'unmapped' and 'pause' since 2.0
##
{ 'enum': 'QKeyCode',
- 'data': [ 'shift', 'shift_r', 'alt', 'alt_r', 'altgr', 'altgr_r', 'ctrl',
+ 'data': [ 'unmapped',
+ 'shift', 'shift_r', 'alt', 'alt_r', 'altgr', 'altgr_r', 'ctrl',
'ctrl_r', 'menu', 'esc', '1', '2', '3', '4', '5', '6', '7', '8',
'9', '0', 'minus', 'equal', 'backspace', 'tab', 'q', 'w', 'e',
'r', 't', 'y', 'u', 'i', 'o', 'p', 'bracket_left', 'bracket_right',
@@ -3571,7 +3574,7 @@
'kp_9', 'less', 'f11', 'f12', 'print', 'home', 'pgup', 'pgdn', 'end',
'left', 'up', 'down', 'right', 'insert', 'delete', 'stop', 'again',
'props', 'undo', 'front', 'copy', 'open', 'paste', 'find', 'cut',
- 'lf', 'help', 'meta_l', 'meta_r', 'compose' ] }
+ 'lf', 'help', 'meta_l', 'meta_r', 'compose', 'pause' ] }
##
# @KeyValue
@@ -4566,3 +4569,79 @@
# Since: 1.7
##
{ 'command': 'blockdev-add', 'data': { 'options': 'BlockdevOptions' } }
+
+##
+# @InputButton
+#
+# Button of a pointer input device (mouse, tablet).
+#
+# Since: 2.0
+##
+{ 'enum' : 'InputButton',
+ 'data' : [ 'Left', 'Middle', 'Right', 'WheelUp', 'WheelDown' ] }
+
+##
+# @InputButton
+#
+# Position axis of a pointer input device (mouse, tablet).
+#
+# Since: 2.0
+##
+{ 'enum' : 'InputAxis',
+ 'data' : [ 'X', 'Y' ] }
+
+##
+# @InputKeyEvent
+#
+# Keyboard input event.
+#
+# @key: Which key this event is for.
+# @down: True for key-down and false for key-up events.
+#
+# Since: 2.0
+##
+{ 'type' : 'InputKeyEvent',
+ 'data' : { 'key' : 'KeyValue',
+ 'down' : 'bool' } }
+
+##
+# @InputBtnEvent
+#
+# Pointer button input event.
+#
+# @button: Which button this event is for.
+# @down: True for key-down and false for key-up events.
+#
+# Since: 2.0
+##
+{ 'type' : 'InputBtnEvent',
+ 'data' : { 'button' : 'InputButton',
+ 'down' : 'bool' } }
+
+##
+# @InputMoveEvent
+#
+# Pointer motion input event.
+#
+# @axis: Which axis is referenced by @value.
+# @value: Pointer position. For absolute coordinates the
+# valid range is 0 -> 0x7ffff
+#
+# Since: 2.0
+##
+{ 'type' : 'InputMoveEvent',
+ 'data' : { 'axis' : 'InputAxis',
+ 'value' : 'int' } }
+
+##
+# @InputEvent
+#
+# Input event union.
+#
+# Since: 2.0
+##
+{ 'union' : 'InputEvent',
+ 'data' : { 'key' : 'InputKeyEvent',
+ 'btn' : 'InputBtnEvent',
+ 'rel' : 'InputMoveEvent',
+ 'abs' : 'InputMoveEvent' } }
diff --git a/qtest.c b/qtest.c
index ae941d6551..0ac9f429f5 100644
--- a/qtest.c
+++ b/qtest.c
@@ -500,7 +500,7 @@ static void qtest_event(void *opaque, int event)
}
}
-int qtest_init_accel(void)
+int qtest_init_accel(QEMUMachine *machine)
{
configure_icount("0");
diff --git a/target-ppc/STATUS b/target-ppc/STATUS
index c8e9018bfc..a4d48a7ca2 100644
--- a/target-ppc/STATUS
+++ b/target-ppc/STATUS
@@ -377,15 +377,6 @@ MMU OK
EXCP KO partially implemented
Remarks: Should be able to boot but there is no hw platform currently emulated.
-PowerPC 970GX:
-INSN KO Altivec missing and more
-SPR KO
-MSR ?
-IRQ OK
-MMU OK
-EXCP KO partially implemented
-Remarks: Should be able to boot but there is no hw platform currently emulated.
-
PowerPC Cell:
INSN KO Altivec missing and more
SPR KO
diff --git a/target-ppc/cpu-models.c b/target-ppc/cpu-models.c
index 7c9466fc07..f6c9b3ab01 100644
--- a/target-ppc/cpu-models.c
+++ b/target-ppc/cpu-models.c
@@ -1156,8 +1156,6 @@
"PowerPC 970FX v3.0 (G5)")
POWERPC_DEF("970fx_v3.1", CPU_POWERPC_970FX_v31, 970FX,
"PowerPC 970FX v3.1 (G5)")
- POWERPC_DEF("970gx", CPU_POWERPC_970GX, 970GX,
- "PowerPC 970GX (G5)")
POWERPC_DEF("970mp_v1.0", CPU_POWERPC_970MP_v10, 970MP,
"PowerPC 970MP v1.0")
POWERPC_DEF("970mp_v1.1", CPU_POWERPC_970MP_v11, 970MP,
diff --git a/target-ppc/cpu-models.h b/target-ppc/cpu-models.h
index 49ba4a4522..644a126459 100644
--- a/target-ppc/cpu-models.h
+++ b/target-ppc/cpu-models.h
@@ -570,7 +570,6 @@ enum {
CPU_POWERPC_970FX_v21 = 0x003C0201,
CPU_POWERPC_970FX_v30 = 0x003C0300,
CPU_POWERPC_970FX_v31 = 0x003C0301,
- CPU_POWERPC_970GX = 0x00450000,
CPU_POWERPC_970MP_v10 = 0x00440100,
CPU_POWERPC_970MP_v11 = 0x00440101,
#define CPU_POWERPC_CELL CPU_POWERPC_CELL_v32
diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h
index 72b22329b0..b17c024543 100644
--- a/target-ppc/cpu-qom.h
+++ b/target-ppc/cpu-qom.h
@@ -79,6 +79,7 @@ typedef struct PowerPCCPUClass {
/**
* PowerPCCPU:
* @env: #CPUPPCState
+ * @cpu_dt_id: CPU index used in the device tree. KVM uses this index too
*
* A PowerPC CPU.
*/
@@ -88,6 +89,7 @@ typedef struct PowerPCCPU {
/*< public >*/
CPUPPCState env;
+ int cpu_dt_id;
} PowerPCCPU;
static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index bb847676a5..afab267485 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -352,6 +352,10 @@ union ppc_avr_t {
int16_t s16[8];
int32_t s32[4];
uint64_t u64[2];
+ int64_t s64[2];
+#ifdef CONFIG_INT128
+ __uint128_t u128;
+#endif
};
#if !defined(CONFIG_USER_ONLY)
@@ -926,6 +930,7 @@ struct CPUPPCState {
target_ulong reserve_addr;
/* Reservation value */
target_ulong reserve_val;
+ target_ulong reserve_val2;
/* Reservation store address */
target_ulong reserve_ea;
/* Reserved store source register and size */
@@ -961,6 +966,7 @@ struct CPUPPCState {
#endif
/* segment registers */
hwaddr htab_base;
+ /* mask used to normalize hash value to PTEG index */
hwaddr htab_mask;
target_ulong sr[32];
/* externally stored hash table */
@@ -1250,7 +1256,7 @@ static inline int cpu_mmu_index (CPUPPCState *env)
#define SPR_MPC_EIE (0x050)
#define SPR_MPC_EID (0x051)
#define SPR_MPC_NRI (0x052)
-#define SPR_CTRL (0x088)
+#define SPR_UCTRL (0x088)
#define SPR_MPC_CMPA (0x090)
#define SPR_MPC_CMPB (0x091)
#define SPR_MPC_CMPC (0x092)
@@ -1259,7 +1265,7 @@ static inline int cpu_mmu_index (CPUPPCState *env)
#define SPR_MPC_DER (0x095)
#define SPR_MPC_COUNTA (0x096)
#define SPR_MPC_COUNTB (0x097)
-#define SPR_UCTRL (0x098)
+#define SPR_CTRL (0x098)
#define SPR_MPC_CMPE (0x098)
#define SPR_MPC_CMPF (0x099)
#define SPR_MPC_CMPG (0x09A)
@@ -1322,12 +1328,12 @@ static inline int cpu_mmu_index (CPUPPCState *env)
#define SPR_BOOKE_IAC3 (0x13A)
#define SPR_HSRR1 (0x13B)
#define SPR_BOOKE_IAC4 (0x13B)
-#define SPR_LPCR (0x13C)
#define SPR_BOOKE_DAC1 (0x13C)
#define SPR_LPIDR (0x13D)
#define SPR_DABR2 (0x13D)
#define SPR_BOOKE_DAC2 (0x13D)
#define SPR_BOOKE_DVC1 (0x13E)
+#define SPR_LPCR (0x13E)
#define SPR_BOOKE_DVC2 (0x13F)
#define SPR_BOOKE_TSR (0x150)
#define SPR_BOOKE_TCR (0x154)
@@ -1508,6 +1514,7 @@ static inline int cpu_mmu_index (CPUPPCState *env)
#define SPR_RCPU_L2U_RA2 (0x32A)
#define SPR_MPC_MD_DBRAM1 (0x32A)
#define SPR_RCPU_L2U_RA3 (0x32B)
+#define SPR_TAR (0x32F)
#define SPR_440_INV0 (0x370)
#define SPR_440_INV1 (0x371)
#define SPR_440_INV2 (0x372)
@@ -1875,9 +1882,31 @@ enum {
PPC2_DBRX = 0x0000000000000010ULL,
/* Book I 2.05 PowerPC specification */
PPC2_ISA205 = 0x0000000000000020ULL,
+ /* VSX additions in ISA 2.07 */
+ PPC2_VSX207 = 0x0000000000000040ULL,
+ /* ISA 2.06B bpermd */
+ PPC2_PERM_ISA206 = 0x0000000000000080ULL,
+ /* ISA 2.06B divide extended variants */
+ PPC2_DIVE_ISA206 = 0x0000000000000100ULL,
+ /* ISA 2.06B larx/stcx. instructions */
+ PPC2_ATOMIC_ISA206 = 0x0000000000000200ULL,
+ /* ISA 2.06B floating point integer conversion */
+ PPC2_FP_CVT_ISA206 = 0x0000000000000400ULL,
+ /* ISA 2.06B floating point test instructions */
+ PPC2_FP_TST_ISA206 = 0x0000000000000800ULL,
+ /* ISA 2.07 bctar instruction */
+ PPC2_BCTAR_ISA207 = 0x0000000000001000ULL,
+ /* ISA 2.07 load/store quadword */
+ PPC2_LSQ_ISA207 = 0x0000000000002000ULL,
+ /* ISA 2.07 Altivec */
+ PPC2_ALTIVEC_207 = 0x0000000000004000ULL,
#define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \
- PPC2_ISA205)
+ PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \
+ PPC2_DIVE_ISA206 | PPC2_ATOMIC_ISA206 | \
+ PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | \
+ PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | \
+ PPC2_ALTIVEC_207)
};
/*****************************************************************************/
@@ -2154,4 +2183,22 @@ static inline bool cpu_has_work(CPUState *cpu)
void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env);
+/**
+ * ppc_get_vcpu_dt_id:
+ * @cs: a PowerPCCPU struct.
+ *
+ * Returns a device-tree ID for a CPU.
+ */
+int ppc_get_vcpu_dt_id(PowerPCCPU *cpu);
+
+/**
+ * ppc_get_vcpu_by_dt_id:
+ * @cpu_dt_id: a device tree id
+ *
+ * Searches for a CPU by @cpu_dt_id.
+ *
+ * Returns: a PowerPCCPU struct
+ */
+PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id);
+
#endif /* !defined (__CPU_PPC_H__) */
diff --git a/target-ppc/fpu_helper.c b/target-ppc/fpu_helper.c
index 4f6021835f..e7f329566d 100644
--- a/target-ppc/fpu_helper.c
+++ b/target-ppc/fpu_helper.c
@@ -50,6 +50,16 @@ static inline int isden(float64 d)
return ((u.ll >> 52) & 0x7FF) == 0;
}
+static inline int ppc_float32_get_unbiased_exp(float32 f)
+{
+ return ((f >> 23) & 0xFF) - 127;
+}
+
+static inline int ppc_float64_get_unbiased_exp(float64 f)
+{
+ return ((f >> 52) & 0x7FF) - 1023;
+}
+
uint32_t helper_compute_fprf(CPUPPCState *env, uint64_t arg, uint32_t set_fprf)
{
CPU_DoubleU farg;
@@ -106,7 +116,8 @@ uint32_t helper_compute_fprf(CPUPPCState *env, uint64_t arg, uint32_t set_fprf)
}
/* Floating-point invalid operations exception */
-static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op)
+static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op,
+ int set_fpcc)
{
uint64_t ret = 0;
int ve;
@@ -138,8 +149,10 @@ static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op)
case POWERPC_EXCP_FP_VXVC:
/* Ordered comparison of NaN */
env->fpscr |= 1 << FPSCR_VXVC;
- env->fpscr &= ~(0xF << FPSCR_FPCC);
- env->fpscr |= 0x11 << FPSCR_FPCC;
+ if (set_fpcc) {
+ env->fpscr &= ~(0xF << FPSCR_FPCC);
+ env->fpscr |= 0x11 << FPSCR_FPCC;
+ }
/* We must update the target FPR before raising the exception */
if (ve != 0) {
env->exception_index = POWERPC_EXCP_PROGRAM;
@@ -158,8 +171,10 @@ static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op)
if (ve == 0) {
/* Set the result to quiet NaN */
ret = 0x7FF8000000000000ULL;
- env->fpscr &= ~(0xF << FPSCR_FPCC);
- env->fpscr |= 0x11 << FPSCR_FPCC;
+ if (set_fpcc) {
+ env->fpscr &= ~(0xF << FPSCR_FPCC);
+ env->fpscr |= 0x11 << FPSCR_FPCC;
+ }
}
break;
case POWERPC_EXCP_FP_VXCVI:
@@ -169,8 +184,10 @@ static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op)
if (ve == 0) {
/* Set the result to quiet NaN */
ret = 0x7FF8000000000000ULL;
- env->fpscr &= ~(0xF << FPSCR_FPCC);
- env->fpscr |= 0x11 << FPSCR_FPCC;
+ if (set_fpcc) {
+ env->fpscr &= ~(0xF << FPSCR_FPCC);
+ env->fpscr |= 0x11 << FPSCR_FPCC;
+ }
}
break;
}
@@ -505,12 +522,12 @@ uint64_t helper_fadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
/* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d))) {
/* sNaN addition */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
}
@@ -529,12 +546,12 @@ uint64_t helper_fsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
/* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d))) {
/* sNaN subtraction */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
}
@@ -553,12 +570,12 @@ uint64_t helper_fmul(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
(float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d))) {
/* sNaN multiplication */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
}
@@ -577,15 +594,15 @@ uint64_t helper_fdiv(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
if (unlikely(float64_is_infinity(farg1.d) &&
float64_is_infinity(farg2.d))) {
/* Division of infinity by infinity */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1);
} else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
/* Division of zero by zero */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d))) {
/* sNaN division */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
}
@@ -593,107 +610,63 @@ uint64_t helper_fdiv(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
return farg1.ll;
}
-/* fctiw - fctiw. */
-uint64_t helper_fctiw(CPUPPCState *env, uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN conversion */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) ||
- float64_is_infinity(farg.d))) {
- /* qNan / infinity conversion */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI);
- } else {
- farg.ll = float64_to_int32(farg.d, &env->fp_status);
- /* XXX: higher bits are not supposed to be significant.
- * to make tests easier, return the same as a real PowerPC 750
- */
- farg.ll |= 0xFFF80000ULL << 32;
- }
- return farg.ll;
-}
-
-/* fctiwz - fctiwz. */
-uint64_t helper_fctiwz(CPUPPCState *env, uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN conversion */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) ||
- float64_is_infinity(farg.d))) {
- /* qNan / infinity conversion */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI);
- } else {
- farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
- /* XXX: higher bits are not supposed to be significant.
- * to make tests easier, return the same as a real PowerPC 750
- */
- farg.ll |= 0xFFF80000ULL << 32;
- }
- return farg.ll;
-}
+#define FPU_FCTI(op, cvt, nanval) \
+uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \
+{ \
+ CPU_DoubleU farg; \
+ \
+ farg.ll = arg; \
+ farg.ll = float64_to_##cvt(farg.d, &env->fp_status); \
+ \
+ if (unlikely(env->fp_status.float_exception_flags)) { \
+ if (float64_is_any_nan(arg)) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1); \
+ if (float64_is_signaling_nan(arg)) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); \
+ } \
+ farg.ll = nanval; \
+ } else if (env->fp_status.float_exception_flags & \
+ float_flag_invalid) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1); \
+ } \
+ helper_float_check_status(env); \
+ } \
+ return farg.ll; \
+ }
+
+FPU_FCTI(fctiw, int32, 0x80000000U)
+FPU_FCTI(fctiwz, int32_round_to_zero, 0x80000000U)
+FPU_FCTI(fctiwu, uint32, 0x00000000U)
+FPU_FCTI(fctiwuz, uint32_round_to_zero, 0x00000000U)
#if defined(TARGET_PPC64)
-/* fcfid - fcfid. */
-uint64_t helper_fcfid(CPUPPCState *env, uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.d = int64_to_float64(arg, &env->fp_status);
- return farg.ll;
-}
-
-/* fctid - fctid. */
-uint64_t helper_fctid(CPUPPCState *env, uint64_t arg)
-{
- CPU_DoubleU farg;
-
- farg.ll = arg;
-
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN conversion */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) ||
- float64_is_infinity(farg.d))) {
- /* qNan / infinity conversion */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI);
- } else {
- farg.ll = float64_to_int64(farg.d, &env->fp_status);
- }
- return farg.ll;
-}
-
-/* fctidz - fctidz. */
-uint64_t helper_fctidz(CPUPPCState *env, uint64_t arg)
-{
- CPU_DoubleU farg;
+FPU_FCTI(fctid, int64, 0x8000000000000000ULL)
+FPU_FCTI(fctidz, int64_round_to_zero, 0x8000000000000000ULL)
+FPU_FCTI(fctidu, uint64, 0x0000000000000000ULL)
+FPU_FCTI(fctiduz, uint64_round_to_zero, 0x0000000000000000ULL)
+#endif
- farg.ll = arg;
+#if defined(TARGET_PPC64)
- if (unlikely(float64_is_signaling_nan(farg.d))) {
- /* sNaN conversion */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) ||
- float64_is_infinity(farg.d))) {
- /* qNan / infinity conversion */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI);
- } else {
- farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
- }
- return farg.ll;
-}
+#define FPU_FCFI(op, cvtr, is_single) \
+uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \
+{ \
+ CPU_DoubleU farg; \
+ \
+ if (is_single) { \
+ float32 tmp = cvtr(arg, &env->fp_status); \
+ farg.d = float32_to_float64(tmp, &env->fp_status); \
+ } else { \
+ farg.d = cvtr(arg, &env->fp_status); \
+ } \
+ helper_float_check_status(env); \
+ return farg.ll; \
+}
+
+FPU_FCFI(fcfid, int64_to_float64, 0)
+FPU_FCFI(fcfids, int64_to_float32, 1)
+FPU_FCFI(fcfidu, uint64_to_float64, 0)
+FPU_FCFI(fcfidus, uint64_to_float32, 1)
#endif
@@ -706,24 +679,28 @@ static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg,
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN round */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXCVI);
- } else if (unlikely(float64_is_quiet_nan(farg.d) ||
- float64_is_infinity(farg.d))) {
- /* qNan / infinity round */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
+ farg.ll = arg | 0x0008000000000000ULL;
} else {
+ int inexact = get_float_exception_flags(&env->fp_status) &
+ float_flag_inexact;
set_float_rounding_mode(rounding_mode, &env->fp_status);
farg.ll = float64_round_to_int(farg.d, &env->fp_status);
/* Restore rounding mode from FPSCR */
fpscr_set_rounding_mode(env);
+
+ /* fri* does not set FPSCR[XX] */
+ if (!inexact) {
+ env->fp_status.float_exception_flags &= ~float_flag_inexact;
+ }
}
+ helper_float_check_status(env);
return farg.ll;
}
uint64_t helper_frin(CPUPPCState *env, uint64_t arg)
{
- return do_fri(env, arg, float_round_nearest_even);
+ return do_fri(env, arg, float_round_ties_away);
}
uint64_t helper_friz(CPUPPCState *env, uint64_t arg)
@@ -754,13 +731,13 @@ uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
(float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d) ||
float64_is_signaling_nan(farg3.d))) {
/* sNaN operation */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
/* This is the way the PowerPC specification defines it */
float128 ft0_128, ft1_128;
@@ -772,7 +749,7 @@ uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
float64_is_infinity(farg3.d) &&
float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
/* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
} else {
ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
@@ -797,13 +774,13 @@ uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
(float64_is_zero(farg1.d) &&
float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d) ||
float64_is_signaling_nan(farg3.d))) {
/* sNaN operation */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
/* This is the way the PowerPC specification defines it */
float128 ft0_128, ft1_128;
@@ -815,7 +792,7 @@ uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
float64_is_infinity(farg3.d) &&
float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
/* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
} else {
ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
@@ -838,13 +815,13 @@ uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
(float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d) ||
float64_is_signaling_nan(farg3.d))) {
/* sNaN operation */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
/* This is the way the PowerPC specification defines it */
float128 ft0_128, ft1_128;
@@ -856,7 +833,7 @@ uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
float64_is_infinity(farg3.d) &&
float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
/* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
} else {
ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
@@ -883,13 +860,13 @@ uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
(float64_is_zero(farg1.d) &&
float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d) ||
float64_is_signaling_nan(farg3.d))) {
/* sNaN operation */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
/* This is the way the PowerPC specification defines it */
float128 ft0_128, ft1_128;
@@ -901,7 +878,7 @@ uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
float64_is_infinity(farg3.d) &&
float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
/* Magnitude subtraction of infinities */
- farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI);
+ farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
} else {
ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
@@ -924,7 +901,7 @@ uint64_t helper_frsp(CPUPPCState *env, uint64_t arg)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN square root */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
f32 = float64_to_float32(farg.d, &env->fp_status);
farg.d = float32_to_float64(f32, &env->fp_status);
@@ -941,11 +918,11 @@ uint64_t helper_fsqrt(CPUPPCState *env, uint64_t arg)
if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
/* Square root of a negative nonzero number */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT);
+ farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN square root */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
farg.d = float64_sqrt(farg.d, &env->fp_status);
}
@@ -961,7 +938,7 @@ uint64_t helper_fre(CPUPPCState *env, uint64_t arg)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN reciprocal */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
farg.d = float64_div(float64_one, farg.d, &env->fp_status);
return farg.d;
@@ -977,7 +954,7 @@ uint64_t helper_fres(CPUPPCState *env, uint64_t arg)
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN reciprocal */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
farg.d = float64_div(float64_one, farg.d, &env->fp_status);
f32 = float64_to_float32(farg.d, &env->fp_status);
@@ -996,11 +973,11 @@ uint64_t helper_frsqrte(CPUPPCState *env, uint64_t arg)
if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
/* Reciprocal square root of a negative nonzero number */
- farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT);
+ farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN reciprocal square root */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
farg.d = float64_sqrt(farg.d, &env->fp_status);
farg.d = float64_div(float64_one, farg.d, &env->fp_status);
@@ -1026,6 +1003,73 @@ uint64_t helper_fsel(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
}
}
+uint32_t helper_ftdiv(uint64_t fra, uint64_t frb)
+{
+ int fe_flag = 0;
+ int fg_flag = 0;
+
+ if (unlikely(float64_is_infinity(fra) ||
+ float64_is_infinity(frb) ||
+ float64_is_zero(frb))) {
+ fe_flag = 1;
+ fg_flag = 1;
+ } else {
+ int e_a = ppc_float64_get_unbiased_exp(fra);
+ int e_b = ppc_float64_get_unbiased_exp(frb);
+
+ if (unlikely(float64_is_any_nan(fra) ||
+ float64_is_any_nan(frb))) {
+ fe_flag = 1;
+ } else if ((e_b <= -1022) || (e_b >= 1021)) {
+ fe_flag = 1;
+ } else if (!float64_is_zero(fra) &&
+ (((e_a - e_b) >= 1023) ||
+ ((e_a - e_b) <= -1021) ||
+ (e_a <= -970))) {
+ fe_flag = 1;
+ }
+
+ if (unlikely(float64_is_zero_or_denormal(frb))) {
+ /* XB is not zero because of the above check and */
+ /* so must be denormalized. */
+ fg_flag = 1;
+ }
+ }
+
+ return 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0);
+}
+
+uint32_t helper_ftsqrt(uint64_t frb)
+{
+ int fe_flag = 0;
+ int fg_flag = 0;
+
+ if (unlikely(float64_is_infinity(frb) || float64_is_zero(frb))) {
+ fe_flag = 1;
+ fg_flag = 1;
+ } else {
+ int e_b = ppc_float64_get_unbiased_exp(frb);
+
+ if (unlikely(float64_is_any_nan(frb))) {
+ fe_flag = 1;
+ } else if (unlikely(float64_is_zero(frb))) {
+ fe_flag = 1;
+ } else if (unlikely(float64_is_neg(frb))) {
+ fe_flag = 1;
+ } else if (!float64_is_zero(frb) && (e_b <= (-1022+52))) {
+ fe_flag = 1;
+ }
+
+ if (unlikely(float64_is_zero_or_denormal(frb))) {
+ /* XB is not zero because of the above check and */
+ /* therefore must be denormalized. */
+ fg_flag = 1;
+ }
+ }
+
+ return 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0);
+}
+
void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
uint32_t crfD)
{
@@ -1053,7 +1097,7 @@ void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
&& (float64_is_signaling_nan(farg1.d) ||
float64_is_signaling_nan(farg2.d)))) {
/* sNaN comparison */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
}
@@ -1085,10 +1129,10 @@ void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
float64_is_signaling_nan(farg2.d)) {
/* sNaN comparison */
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN |
- POWERPC_EXCP_FP_VXVC);
+ POWERPC_EXCP_FP_VXVC, 1);
} else {
/* qNaN comparison */
- fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC);
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 1);
}
}
}
@@ -1710,3 +1754,969 @@ uint32_t helper_efdcmpeq(CPUPPCState *env, uint64_t op1, uint64_t op2)
/* XXX: TODO: test special values (NaN, infinites, ...) */
return helper_efdtsteq(env, op1, op2);
}
+
+#define DECODE_SPLIT(opcode, shift1, nb1, shift2, nb2) \
+ (((((opcode) >> (shift1)) & ((1 << (nb1)) - 1)) << nb2) | \
+ (((opcode) >> (shift2)) & ((1 << (nb2)) - 1)))
+
+#define xT(opcode) DECODE_SPLIT(opcode, 0, 1, 21, 5)
+#define xA(opcode) DECODE_SPLIT(opcode, 2, 1, 16, 5)
+#define xB(opcode) DECODE_SPLIT(opcode, 1, 1, 11, 5)
+#define xC(opcode) DECODE_SPLIT(opcode, 3, 1, 6, 5)
+#define BF(opcode) (((opcode) >> (31-8)) & 7)
+
+typedef union _ppc_vsr_t {
+ uint64_t u64[2];
+ uint32_t u32[4];
+ float32 f32[4];
+ float64 f64[2];
+} ppc_vsr_t;
+
+static void getVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env)
+{
+ if (n < 32) {
+ vsr->f64[0] = env->fpr[n];
+ vsr->u64[1] = env->vsr[n];
+ } else {
+ vsr->u64[0] = env->avr[n-32].u64[0];
+ vsr->u64[1] = env->avr[n-32].u64[1];
+ }
+}
+
+static void putVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env)
+{
+ if (n < 32) {
+ env->fpr[n] = vsr->f64[0];
+ env->vsr[n] = vsr->u64[1];
+ } else {
+ env->avr[n-32].u64[0] = vsr->u64[0];
+ env->avr[n-32].u64[1] = vsr->u64[1];
+ }
+}
+
+#define float64_to_float64(x, env) x
+
+
+/* VSX_ADD_SUB - VSX floating point add/subract
+ * name - instruction mnemonic
+ * op - operation (add or sub)
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ * sfprf - set FPRF
+ */
+#define VSX_ADD_SUB(name, op, nels, tp, fld, sfprf, r2sp) \
+void helper_##name(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xa, xb; \
+ int i; \
+ \
+ getVSR(xA(opcode), &xa, env); \
+ getVSR(xB(opcode), &xb, env); \
+ getVSR(xT(opcode), &xt, env); \
+ helper_reset_fpstatus(env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ float_status tstat = env->fp_status; \
+ set_float_exception_flags(0, &tstat); \
+ xt.fld[i] = tp##_##op(xa.fld[i], xb.fld[i], &tstat); \
+ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
+ \
+ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
+ if (tp##_is_infinity(xa.fld[i]) && tp##_is_infinity(xb.fld[i])) {\
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf); \
+ } else if (tp##_is_signaling_nan(xa.fld[i]) || \
+ tp##_is_signaling_nan(xb.fld[i])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
+ } \
+ } \
+ \
+ if (r2sp) { \
+ xt.fld[i] = helper_frsp(env, xt.fld[i]); \
+ } \
+ \
+ if (sfprf) { \
+ helper_compute_fprf(env, xt.fld[i], sfprf); \
+ } \
+ } \
+ putVSR(xT(opcode), &xt, env); \
+ helper_float_check_status(env); \
+}
+
+VSX_ADD_SUB(xsadddp, add, 1, float64, f64, 1, 0)
+VSX_ADD_SUB(xsaddsp, add, 1, float64, f64, 1, 1)
+VSX_ADD_SUB(xvadddp, add, 2, float64, f64, 0, 0)
+VSX_ADD_SUB(xvaddsp, add, 4, float32, f32, 0, 0)
+VSX_ADD_SUB(xssubdp, sub, 1, float64, f64, 1, 0)
+VSX_ADD_SUB(xssubsp, sub, 1, float64, f64, 1, 1)
+VSX_ADD_SUB(xvsubdp, sub, 2, float64, f64, 0, 0)
+VSX_ADD_SUB(xvsubsp, sub, 4, float32, f32, 0, 0)
+
+/* VSX_MUL - VSX floating point multiply
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ * sfprf - set FPRF
+ */
+#define VSX_MUL(op, nels, tp, fld, sfprf, r2sp) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xa, xb; \
+ int i; \
+ \
+ getVSR(xA(opcode), &xa, env); \
+ getVSR(xB(opcode), &xb, env); \
+ getVSR(xT(opcode), &xt, env); \
+ helper_reset_fpstatus(env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ float_status tstat = env->fp_status; \
+ set_float_exception_flags(0, &tstat); \
+ xt.fld[i] = tp##_mul(xa.fld[i], xb.fld[i], &tstat); \
+ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
+ \
+ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
+ if ((tp##_is_infinity(xa.fld[i]) && tp##_is_zero(xb.fld[i])) || \
+ (tp##_is_infinity(xb.fld[i]) && tp##_is_zero(xa.fld[i]))) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, sfprf); \
+ } else if (tp##_is_signaling_nan(xa.fld[i]) || \
+ tp##_is_signaling_nan(xb.fld[i])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
+ } \
+ } \
+ \
+ if (r2sp) { \
+ xt.fld[i] = helper_frsp(env, xt.fld[i]); \
+ } \
+ \
+ if (sfprf) { \
+ helper_compute_fprf(env, xt.fld[i], sfprf); \
+ } \
+ } \
+ \
+ putVSR(xT(opcode), &xt, env); \
+ helper_float_check_status(env); \
+}
+
+VSX_MUL(xsmuldp, 1, float64, f64, 1, 0)
+VSX_MUL(xsmulsp, 1, float64, f64, 1, 1)
+VSX_MUL(xvmuldp, 2, float64, f64, 0, 0)
+VSX_MUL(xvmulsp, 4, float32, f32, 0, 0)
+
+/* VSX_DIV - VSX floating point divide
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ * sfprf - set FPRF
+ */
+#define VSX_DIV(op, nels, tp, fld, sfprf, r2sp) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xa, xb; \
+ int i; \
+ \
+ getVSR(xA(opcode), &xa, env); \
+ getVSR(xB(opcode), &xb, env); \
+ getVSR(xT(opcode), &xt, env); \
+ helper_reset_fpstatus(env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ float_status tstat = env->fp_status; \
+ set_float_exception_flags(0, &tstat); \
+ xt.fld[i] = tp##_div(xa.fld[i], xb.fld[i], &tstat); \
+ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
+ \
+ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
+ if (tp##_is_infinity(xa.fld[i]) && tp##_is_infinity(xb.fld[i])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, sfprf); \
+ } else if (tp##_is_zero(xa.fld[i]) && \
+ tp##_is_zero(xb.fld[i])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, sfprf); \
+ } else if (tp##_is_signaling_nan(xa.fld[i]) || \
+ tp##_is_signaling_nan(xb.fld[i])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
+ } \
+ } \
+ \
+ if (r2sp) { \
+ xt.fld[i] = helper_frsp(env, xt.fld[i]); \
+ } \
+ \
+ if (sfprf) { \
+ helper_compute_fprf(env, xt.fld[i], sfprf); \
+ } \
+ } \
+ \
+ putVSR(xT(opcode), &xt, env); \
+ helper_float_check_status(env); \
+}
+
+VSX_DIV(xsdivdp, 1, float64, f64, 1, 0)
+VSX_DIV(xsdivsp, 1, float64, f64, 1, 1)
+VSX_DIV(xvdivdp, 2, float64, f64, 0, 0)
+VSX_DIV(xvdivsp, 4, float32, f32, 0, 0)
+
+/* VSX_RE - VSX floating point reciprocal estimate
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ * sfprf - set FPRF
+ */
+#define VSX_RE(op, nels, tp, fld, sfprf, r2sp) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xb; \
+ int i; \
+ \
+ getVSR(xB(opcode), &xb, env); \
+ getVSR(xT(opcode), &xt, env); \
+ helper_reset_fpstatus(env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ if (unlikely(tp##_is_signaling_nan(xb.fld[i]))) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
+ } \
+ xt.fld[i] = tp##_div(tp##_one, xb.fld[i], &env->fp_status); \
+ \
+ if (r2sp) { \
+ xt.fld[i] = helper_frsp(env, xt.fld[i]); \
+ } \
+ \
+ if (sfprf) { \
+ helper_compute_fprf(env, xt.fld[0], sfprf); \
+ } \
+ } \
+ \
+ putVSR(xT(opcode), &xt, env); \
+ helper_float_check_status(env); \
+}
+
+VSX_RE(xsredp, 1, float64, f64, 1, 0)
+VSX_RE(xsresp, 1, float64, f64, 1, 1)
+VSX_RE(xvredp, 2, float64, f64, 0, 0)
+VSX_RE(xvresp, 4, float32, f32, 0, 0)
+
+/* VSX_SQRT - VSX floating point square root
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ * sfprf - set FPRF
+ */
+#define VSX_SQRT(op, nels, tp, fld, sfprf, r2sp) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xb; \
+ int i; \
+ \
+ getVSR(xB(opcode), &xb, env); \
+ getVSR(xT(opcode), &xt, env); \
+ helper_reset_fpstatus(env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ float_status tstat = env->fp_status; \
+ set_float_exception_flags(0, &tstat); \
+ xt.fld[i] = tp##_sqrt(xb.fld[i], &tstat); \
+ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
+ \
+ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
+ if (tp##_is_neg(xb.fld[i]) && !tp##_is_zero(xb.fld[i])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf); \
+ } else if (tp##_is_signaling_nan(xb.fld[i])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
+ } \
+ } \
+ \
+ if (r2sp) { \
+ xt.fld[i] = helper_frsp(env, xt.fld[i]); \
+ } \
+ \
+ if (sfprf) { \
+ helper_compute_fprf(env, xt.fld[i], sfprf); \
+ } \
+ } \
+ \
+ putVSR(xT(opcode), &xt, env); \
+ helper_float_check_status(env); \
+}
+
+VSX_SQRT(xssqrtdp, 1, float64, f64, 1, 0)
+VSX_SQRT(xssqrtsp, 1, float64, f64, 1, 1)
+VSX_SQRT(xvsqrtdp, 2, float64, f64, 0, 0)
+VSX_SQRT(xvsqrtsp, 4, float32, f32, 0, 0)
+
+/* VSX_RSQRTE - VSX floating point reciprocal square root estimate
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ * sfprf - set FPRF
+ */
+#define VSX_RSQRTE(op, nels, tp, fld, sfprf, r2sp) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xb; \
+ int i; \
+ \
+ getVSR(xB(opcode), &xb, env); \
+ getVSR(xT(opcode), &xt, env); \
+ helper_reset_fpstatus(env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ float_status tstat = env->fp_status; \
+ set_float_exception_flags(0, &tstat); \
+ xt.fld[i] = tp##_sqrt(xb.fld[i], &tstat); \
+ xt.fld[i] = tp##_div(tp##_one, xt.fld[i], &tstat); \
+ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
+ \
+ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
+ if (tp##_is_neg(xb.fld[i]) && !tp##_is_zero(xb.fld[i])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf); \
+ } else if (tp##_is_signaling_nan(xb.fld[i])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
+ } \
+ } \
+ \
+ if (r2sp) { \
+ xt.fld[i] = helper_frsp(env, xt.fld[i]); \
+ } \
+ \
+ if (sfprf) { \
+ helper_compute_fprf(env, xt.fld[i], sfprf); \
+ } \
+ } \
+ \
+ putVSR(xT(opcode), &xt, env); \
+ helper_float_check_status(env); \
+}
+
+VSX_RSQRTE(xsrsqrtedp, 1, float64, f64, 1, 0)
+VSX_RSQRTE(xsrsqrtesp, 1, float64, f64, 1, 1)
+VSX_RSQRTE(xvrsqrtedp, 2, float64, f64, 0, 0)
+VSX_RSQRTE(xvrsqrtesp, 4, float32, f32, 0, 0)
+
+/* VSX_TDIV - VSX floating point test for divide
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ * emin - minimum unbiased exponent
+ * emax - maximum unbiased exponent
+ * nbits - number of fraction bits
+ */
+#define VSX_TDIV(op, nels, tp, fld, emin, emax, nbits) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xa, xb; \
+ int i; \
+ int fe_flag = 0; \
+ int fg_flag = 0; \
+ \
+ getVSR(xA(opcode), &xa, env); \
+ getVSR(xB(opcode), &xb, env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ if (unlikely(tp##_is_infinity(xa.fld[i]) || \
+ tp##_is_infinity(xb.fld[i]) || \
+ tp##_is_zero(xb.fld[i]))) { \
+ fe_flag = 1; \
+ fg_flag = 1; \
+ } else { \
+ int e_a = ppc_##tp##_get_unbiased_exp(xa.fld[i]); \
+ int e_b = ppc_##tp##_get_unbiased_exp(xb.fld[i]); \
+ \
+ if (unlikely(tp##_is_any_nan(xa.fld[i]) || \
+ tp##_is_any_nan(xb.fld[i]))) { \
+ fe_flag = 1; \
+ } else if ((e_b <= emin) || (e_b >= (emax-2))) { \
+ fe_flag = 1; \
+ } else if (!tp##_is_zero(xa.fld[i]) && \
+ (((e_a - e_b) >= emax) || \
+ ((e_a - e_b) <= (emin+1)) || \
+ (e_a <= (emin+nbits)))) { \
+ fe_flag = 1; \
+ } \
+ \
+ if (unlikely(tp##_is_zero_or_denormal(xb.fld[i]))) { \
+ /* XB is not zero because of the above check and */ \
+ /* so must be denormalized. */ \
+ fg_flag = 1; \
+ } \
+ } \
+ } \
+ \
+ env->crf[BF(opcode)] = 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); \
+}
+
+VSX_TDIV(xstdivdp, 1, float64, f64, -1022, 1023, 52)
+VSX_TDIV(xvtdivdp, 2, float64, f64, -1022, 1023, 52)
+VSX_TDIV(xvtdivsp, 4, float32, f32, -126, 127, 23)
+
+/* VSX_TSQRT - VSX floating point test for square root
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ * emin - minimum unbiased exponent
+ * emax - maximum unbiased exponent
+ * nbits - number of fraction bits
+ */
+#define VSX_TSQRT(op, nels, tp, fld, emin, nbits) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xa, xb; \
+ int i; \
+ int fe_flag = 0; \
+ int fg_flag = 0; \
+ \
+ getVSR(xA(opcode), &xa, env); \
+ getVSR(xB(opcode), &xb, env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ if (unlikely(tp##_is_infinity(xb.fld[i]) || \
+ tp##_is_zero(xb.fld[i]))) { \
+ fe_flag = 1; \
+ fg_flag = 1; \
+ } else { \
+ int e_b = ppc_##tp##_get_unbiased_exp(xb.fld[i]); \
+ \
+ if (unlikely(tp##_is_any_nan(xb.fld[i]))) { \
+ fe_flag = 1; \
+ } else if (unlikely(tp##_is_zero(xb.fld[i]))) { \
+ fe_flag = 1; \
+ } else if (unlikely(tp##_is_neg(xb.fld[i]))) { \
+ fe_flag = 1; \
+ } else if (!tp##_is_zero(xb.fld[i]) && \
+ (e_b <= (emin+nbits))) { \
+ fe_flag = 1; \
+ } \
+ \
+ if (unlikely(tp##_is_zero_or_denormal(xb.fld[i]))) { \
+ /* XB is not zero because of the above check and */ \
+ /* therefore must be denormalized. */ \
+ fg_flag = 1; \
+ } \
+ } \
+ } \
+ \
+ env->crf[BF(opcode)] = 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); \
+}
+
+VSX_TSQRT(xstsqrtdp, 1, float64, f64, -1022, 52)
+VSX_TSQRT(xvtsqrtdp, 2, float64, f64, -1022, 52)
+VSX_TSQRT(xvtsqrtsp, 4, float32, f32, -126, 23)
+
+/* VSX_MADD - VSX floating point muliply/add variations
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ * maddflgs - flags for the float*muladd routine that control the
+ * various forms (madd, msub, nmadd, nmsub)
+ * afrm - A form (1=A, 0=M)
+ * sfprf - set FPRF
+ */
+#define VSX_MADD(op, nels, tp, fld, maddflgs, afrm, sfprf, r2sp) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt_in, xa, xb, xt_out; \
+ ppc_vsr_t *b, *c; \
+ int i; \
+ \
+ if (afrm) { /* AxB + T */ \
+ b = &xb; \
+ c = &xt_in; \
+ } else { /* AxT + B */ \
+ b = &xt_in; \
+ c = &xb; \
+ } \
+ \
+ getVSR(xA(opcode), &xa, env); \
+ getVSR(xB(opcode), &xb, env); \
+ getVSR(xT(opcode), &xt_in, env); \
+ \
+ xt_out = xt_in; \
+ \
+ helper_reset_fpstatus(env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ float_status tstat = env->fp_status; \
+ set_float_exception_flags(0, &tstat); \
+ if (r2sp && (tstat.float_rounding_mode == float_round_nearest_even)) {\
+ /* Avoid double rounding errors by rounding the intermediate */ \
+ /* result to odd. */ \
+ set_float_rounding_mode(float_round_to_zero, &tstat); \
+ xt_out.fld[i] = tp##_muladd(xa.fld[i], b->fld[i], c->fld[i], \
+ maddflgs, &tstat); \
+ xt_out.fld[i] |= (get_float_exception_flags(&tstat) & \
+ float_flag_inexact) != 0; \
+ } else { \
+ xt_out.fld[i] = tp##_muladd(xa.fld[i], b->fld[i], c->fld[i], \
+ maddflgs, &tstat); \
+ } \
+ env->fp_status.float_exception_flags |= tstat.float_exception_flags; \
+ \
+ if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
+ if (tp##_is_signaling_nan(xa.fld[i]) || \
+ tp##_is_signaling_nan(b->fld[i]) || \
+ tp##_is_signaling_nan(c->fld[i])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
+ tstat.float_exception_flags &= ~float_flag_invalid; \
+ } \
+ if ((tp##_is_infinity(xa.fld[i]) && tp##_is_zero(b->fld[i])) || \
+ (tp##_is_zero(xa.fld[i]) && tp##_is_infinity(b->fld[i]))) { \
+ xt_out.fld[i] = float64_to_##tp(fload_invalid_op_excp(env, \
+ POWERPC_EXCP_FP_VXIMZ, sfprf), &env->fp_status); \
+ tstat.float_exception_flags &= ~float_flag_invalid; \
+ } \
+ if ((tstat.float_exception_flags & float_flag_invalid) && \
+ ((tp##_is_infinity(xa.fld[i]) || \
+ tp##_is_infinity(b->fld[i])) && \
+ tp##_is_infinity(c->fld[i]))) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf); \
+ } \
+ } \
+ \
+ if (r2sp) { \
+ xt_out.fld[i] = helper_frsp(env, xt_out.fld[i]); \
+ } \
+ \
+ if (sfprf) { \
+ helper_compute_fprf(env, xt_out.fld[i], sfprf); \
+ } \
+ } \
+ putVSR(xT(opcode), &xt_out, env); \
+ helper_float_check_status(env); \
+}
+
+#define MADD_FLGS 0
+#define MSUB_FLGS float_muladd_negate_c
+#define NMADD_FLGS float_muladd_negate_result
+#define NMSUB_FLGS (float_muladd_negate_c | float_muladd_negate_result)
+
+VSX_MADD(xsmaddadp, 1, float64, f64, MADD_FLGS, 1, 1, 0)
+VSX_MADD(xsmaddmdp, 1, float64, f64, MADD_FLGS, 0, 1, 0)
+VSX_MADD(xsmsubadp, 1, float64, f64, MSUB_FLGS, 1, 1, 0)
+VSX_MADD(xsmsubmdp, 1, float64, f64, MSUB_FLGS, 0, 1, 0)
+VSX_MADD(xsnmaddadp, 1, float64, f64, NMADD_FLGS, 1, 1, 0)
+VSX_MADD(xsnmaddmdp, 1, float64, f64, NMADD_FLGS, 0, 1, 0)
+VSX_MADD(xsnmsubadp, 1, float64, f64, NMSUB_FLGS, 1, 1, 0)
+VSX_MADD(xsnmsubmdp, 1, float64, f64, NMSUB_FLGS, 0, 1, 0)
+
+VSX_MADD(xsmaddasp, 1, float64, f64, MADD_FLGS, 1, 1, 1)
+VSX_MADD(xsmaddmsp, 1, float64, f64, MADD_FLGS, 0, 1, 1)
+VSX_MADD(xsmsubasp, 1, float64, f64, MSUB_FLGS, 1, 1, 1)
+VSX_MADD(xsmsubmsp, 1, float64, f64, MSUB_FLGS, 0, 1, 1)
+VSX_MADD(xsnmaddasp, 1, float64, f64, NMADD_FLGS, 1, 1, 1)
+VSX_MADD(xsnmaddmsp, 1, float64, f64, NMADD_FLGS, 0, 1, 1)
+VSX_MADD(xsnmsubasp, 1, float64, f64, NMSUB_FLGS, 1, 1, 1)
+VSX_MADD(xsnmsubmsp, 1, float64, f64, NMSUB_FLGS, 0, 1, 1)
+
+VSX_MADD(xvmaddadp, 2, float64, f64, MADD_FLGS, 1, 0, 0)
+VSX_MADD(xvmaddmdp, 2, float64, f64, MADD_FLGS, 0, 0, 0)
+VSX_MADD(xvmsubadp, 2, float64, f64, MSUB_FLGS, 1, 0, 0)
+VSX_MADD(xvmsubmdp, 2, float64, f64, MSUB_FLGS, 0, 0, 0)
+VSX_MADD(xvnmaddadp, 2, float64, f64, NMADD_FLGS, 1, 0, 0)
+VSX_MADD(xvnmaddmdp, 2, float64, f64, NMADD_FLGS, 0, 0, 0)
+VSX_MADD(xvnmsubadp, 2, float64, f64, NMSUB_FLGS, 1, 0, 0)
+VSX_MADD(xvnmsubmdp, 2, float64, f64, NMSUB_FLGS, 0, 0, 0)
+
+VSX_MADD(xvmaddasp, 4, float32, f32, MADD_FLGS, 1, 0, 0)
+VSX_MADD(xvmaddmsp, 4, float32, f32, MADD_FLGS, 0, 0, 0)
+VSX_MADD(xvmsubasp, 4, float32, f32, MSUB_FLGS, 1, 0, 0)
+VSX_MADD(xvmsubmsp, 4, float32, f32, MSUB_FLGS, 0, 0, 0)
+VSX_MADD(xvnmaddasp, 4, float32, f32, NMADD_FLGS, 1, 0, 0)
+VSX_MADD(xvnmaddmsp, 4, float32, f32, NMADD_FLGS, 0, 0, 0)
+VSX_MADD(xvnmsubasp, 4, float32, f32, NMSUB_FLGS, 1, 0, 0)
+VSX_MADD(xvnmsubmsp, 4, float32, f32, NMSUB_FLGS, 0, 0, 0)
+
+#define VSX_SCALAR_CMP(op, ordered) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xa, xb; \
+ uint32_t cc = 0; \
+ \
+ getVSR(xA(opcode), &xa, env); \
+ getVSR(xB(opcode), &xb, env); \
+ \
+ if (unlikely(float64_is_any_nan(xa.f64[0]) || \
+ float64_is_any_nan(xb.f64[0]))) { \
+ if (float64_is_signaling_nan(xa.f64[0]) || \
+ float64_is_signaling_nan(xb.f64[0])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
+ } \
+ if (ordered) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \
+ } \
+ cc = 1; \
+ } else { \
+ if (float64_lt(xa.f64[0], xb.f64[0], &env->fp_status)) { \
+ cc = 8; \
+ } else if (!float64_le(xa.f64[0], xb.f64[0], &env->fp_status)) { \
+ cc = 4; \
+ } else { \
+ cc = 2; \
+ } \
+ } \
+ \
+ env->fpscr &= ~(0x0F << FPSCR_FPRF); \
+ env->fpscr |= cc << FPSCR_FPRF; \
+ env->crf[BF(opcode)] = cc; \
+ \
+ helper_float_check_status(env); \
+}
+
+VSX_SCALAR_CMP(xscmpodp, 1)
+VSX_SCALAR_CMP(xscmpudp, 0)
+
+#define float64_snan_to_qnan(x) ((x) | 0x0008000000000000ULL)
+#define float32_snan_to_qnan(x) ((x) | 0x00400000)
+
+/* VSX_MAX_MIN - VSX floating point maximum/minimum
+ * name - instruction mnemonic
+ * op - operation (max or min)
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ */
+#define VSX_MAX_MIN(name, op, nels, tp, fld) \
+void helper_##name(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xa, xb; \
+ int i; \
+ \
+ getVSR(xA(opcode), &xa, env); \
+ getVSR(xB(opcode), &xb, env); \
+ getVSR(xT(opcode), &xt, env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ xt.fld[i] = tp##_##op(xa.fld[i], xb.fld[i], &env->fp_status); \
+ if (unlikely(tp##_is_signaling_nan(xa.fld[i]) || \
+ tp##_is_signaling_nan(xb.fld[i]))) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
+ } \
+ } \
+ \
+ putVSR(xT(opcode), &xt, env); \
+ helper_float_check_status(env); \
+}
+
+VSX_MAX_MIN(xsmaxdp, maxnum, 1, float64, f64)
+VSX_MAX_MIN(xvmaxdp, maxnum, 2, float64, f64)
+VSX_MAX_MIN(xvmaxsp, maxnum, 4, float32, f32)
+VSX_MAX_MIN(xsmindp, minnum, 1, float64, f64)
+VSX_MAX_MIN(xvmindp, minnum, 2, float64, f64)
+VSX_MAX_MIN(xvminsp, minnum, 4, float32, f32)
+
+/* VSX_CMP - VSX floating point compare
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ * cmp - comparison operation
+ * svxvc - set VXVC bit
+ */
+#define VSX_CMP(op, nels, tp, fld, cmp, svxvc) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xa, xb; \
+ int i; \
+ int all_true = 1; \
+ int all_false = 1; \
+ \
+ getVSR(xA(opcode), &xa, env); \
+ getVSR(xB(opcode), &xb, env); \
+ getVSR(xT(opcode), &xt, env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ if (unlikely(tp##_is_any_nan(xa.fld[i]) || \
+ tp##_is_any_nan(xb.fld[i]))) { \
+ if (tp##_is_signaling_nan(xa.fld[i]) || \
+ tp##_is_signaling_nan(xb.fld[i])) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
+ } \
+ if (svxvc) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \
+ } \
+ xt.fld[i] = 0; \
+ all_true = 0; \
+ } else { \
+ if (tp##_##cmp(xb.fld[i], xa.fld[i], &env->fp_status) == 1) { \
+ xt.fld[i] = -1; \
+ all_false = 0; \
+ } else { \
+ xt.fld[i] = 0; \
+ all_true = 0; \
+ } \
+ } \
+ } \
+ \
+ putVSR(xT(opcode), &xt, env); \
+ if ((opcode >> (31-21)) & 1) { \
+ env->crf[6] = (all_true ? 0x8 : 0) | (all_false ? 0x2 : 0); \
+ } \
+ helper_float_check_status(env); \
+ }
+
+VSX_CMP(xvcmpeqdp, 2, float64, f64, eq, 0)
+VSX_CMP(xvcmpgedp, 2, float64, f64, le, 1)
+VSX_CMP(xvcmpgtdp, 2, float64, f64, lt, 1)
+VSX_CMP(xvcmpeqsp, 4, float32, f32, eq, 0)
+VSX_CMP(xvcmpgesp, 4, float32, f32, le, 1)
+VSX_CMP(xvcmpgtsp, 4, float32, f32, lt, 1)
+
+#if defined(HOST_WORDS_BIGENDIAN)
+#define JOFFSET 0
+#else
+#define JOFFSET 1
+#endif
+
+/* VSX_CVT_FP_TO_FP - VSX floating point/floating point conversion
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * stp - source type (float32 or float64)
+ * ttp - target type (float32 or float64)
+ * sfld - source vsr_t field
+ * tfld - target vsr_t field (f32 or f64)
+ * sfprf - set FPRF
+ */
+#define VSX_CVT_FP_TO_FP(op, nels, stp, ttp, sfld, tfld, sfprf) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xb; \
+ int i; \
+ \
+ getVSR(xB(opcode), &xb, env); \
+ getVSR(xT(opcode), &xt, env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ int j = 2*i + JOFFSET; \
+ xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \
+ if (unlikely(stp##_is_signaling_nan(xb.sfld))) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
+ xt.tfld = ttp##_snan_to_qnan(xt.tfld); \
+ } \
+ if (sfprf) { \
+ helper_compute_fprf(env, ttp##_to_float64(xt.tfld, \
+ &env->fp_status), sfprf); \
+ } \
+ } \
+ \
+ putVSR(xT(opcode), &xt, env); \
+ helper_float_check_status(env); \
+}
+
+VSX_CVT_FP_TO_FP(xscvdpsp, 1, float64, float32, f64[i], f32[j], 1)
+VSX_CVT_FP_TO_FP(xscvspdp, 1, float32, float64, f32[j], f64[i], 1)
+VSX_CVT_FP_TO_FP(xvcvdpsp, 2, float64, float32, f64[i], f32[j], 0)
+VSX_CVT_FP_TO_FP(xvcvspdp, 2, float32, float64, f32[j], f64[i], 0)
+
+uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb)
+{
+ float_status tstat = env->fp_status;
+ set_float_exception_flags(0, &tstat);
+
+ return (uint64_t)float64_to_float32(xb, &tstat) << 32;
+}
+
+uint64_t helper_xscvspdpn(CPUPPCState *env, uint64_t xb)
+{
+ float_status tstat = env->fp_status;
+ set_float_exception_flags(0, &tstat);
+
+ return float32_to_float64(xb >> 32, &tstat);
+}
+
+/* VSX_CVT_FP_TO_INT - VSX floating point to integer conversion
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * stp - source type (float32 or float64)
+ * ttp - target type (int32, uint32, int64 or uint64)
+ * sfld - source vsr_t field
+ * tfld - target vsr_t field
+ * jdef - definition of the j index (i or 2*i)
+ * rnan - resulting NaN
+ */
+#define VSX_CVT_FP_TO_INT(op, nels, stp, ttp, sfld, tfld, jdef, rnan) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xb; \
+ int i; \
+ \
+ getVSR(xB(opcode), &xb, env); \
+ getVSR(xT(opcode), &xt, env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ int j = jdef; \
+ if (unlikely(stp##_is_any_nan(xb.sfld))) { \
+ if (stp##_is_signaling_nan(xb.sfld)) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
+ } \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0); \
+ xt.tfld = rnan; \
+ } else { \
+ xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \
+ if (env->fp_status.float_exception_flags & float_flag_invalid) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0); \
+ } \
+ } \
+ } \
+ \
+ putVSR(xT(opcode), &xt, env); \
+ helper_float_check_status(env); \
+}
+
+VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, f64[j], u64[i], i, \
+ 0x8000000000000000ULL)
+VSX_CVT_FP_TO_INT(xscvdpsxws, 1, float64, int32, f64[i], u32[j], \
+ 2*i + JOFFSET, 0x80000000U)
+VSX_CVT_FP_TO_INT(xscvdpuxds, 1, float64, uint64, f64[j], u64[i], i, 0ULL)
+VSX_CVT_FP_TO_INT(xscvdpuxws, 1, float64, uint32, f64[i], u32[j], \
+ 2*i + JOFFSET, 0U)
+VSX_CVT_FP_TO_INT(xvcvdpsxds, 2, float64, int64, f64[j], u64[i], i, \
+ 0x8000000000000000ULL)
+VSX_CVT_FP_TO_INT(xvcvdpsxws, 2, float64, int32, f64[i], u32[j], \
+ 2*i + JOFFSET, 0x80000000U)
+VSX_CVT_FP_TO_INT(xvcvdpuxds, 2, float64, uint64, f64[j], u64[i], i, 0ULL)
+VSX_CVT_FP_TO_INT(xvcvdpuxws, 2, float64, uint32, f64[i], u32[j], \
+ 2*i + JOFFSET, 0U)
+VSX_CVT_FP_TO_INT(xvcvspsxds, 2, float32, int64, f32[j], u64[i], \
+ 2*i + JOFFSET, 0x8000000000000000ULL)
+VSX_CVT_FP_TO_INT(xvcvspsxws, 4, float32, int32, f32[j], u32[j], i, \
+ 0x80000000U)
+VSX_CVT_FP_TO_INT(xvcvspuxds, 2, float32, uint64, f32[j], u64[i], \
+ 2*i + JOFFSET, 0ULL)
+VSX_CVT_FP_TO_INT(xvcvspuxws, 4, float32, uint32, f32[j], u32[i], i, 0U)
+
+/* VSX_CVT_INT_TO_FP - VSX integer to floating point conversion
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * stp - source type (int32, uint32, int64 or uint64)
+ * ttp - target type (float32 or float64)
+ * sfld - source vsr_t field
+ * tfld - target vsr_t field
+ * jdef - definition of the j index (i or 2*i)
+ * sfprf - set FPRF
+ */
+#define VSX_CVT_INT_TO_FP(op, nels, stp, ttp, sfld, tfld, jdef, sfprf, r2sp) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xb; \
+ int i; \
+ \
+ getVSR(xB(opcode), &xb, env); \
+ getVSR(xT(opcode), &xt, env); \
+ \
+ for (i = 0; i < nels; i++) { \
+ int j = jdef; \
+ xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \
+ if (r2sp) { \
+ xt.tfld = helper_frsp(env, xt.tfld); \
+ } \
+ if (sfprf) { \
+ helper_compute_fprf(env, xt.tfld, sfprf); \
+ } \
+ } \
+ \
+ putVSR(xT(opcode), &xt, env); \
+ helper_float_check_status(env); \
+}
+
+VSX_CVT_INT_TO_FP(xscvsxddp, 1, int64, float64, u64[j], f64[i], i, 1, 0)
+VSX_CVT_INT_TO_FP(xscvuxddp, 1, uint64, float64, u64[j], f64[i], i, 1, 0)
+VSX_CVT_INT_TO_FP(xscvsxdsp, 1, int64, float64, u64[j], f64[i], i, 1, 1)
+VSX_CVT_INT_TO_FP(xscvuxdsp, 1, uint64, float64, u64[j], f64[i], i, 1, 1)
+VSX_CVT_INT_TO_FP(xvcvsxddp, 2, int64, float64, u64[j], f64[i], i, 0, 0)
+VSX_CVT_INT_TO_FP(xvcvuxddp, 2, uint64, float64, u64[j], f64[i], i, 0, 0)
+VSX_CVT_INT_TO_FP(xvcvsxwdp, 2, int32, float64, u32[j], f64[i], \
+ 2*i + JOFFSET, 0, 0)
+VSX_CVT_INT_TO_FP(xvcvuxwdp, 2, uint64, float64, u32[j], f64[i], \
+ 2*i + JOFFSET, 0, 0)
+VSX_CVT_INT_TO_FP(xvcvsxdsp, 2, int64, float32, u64[i], f32[j], \
+ 2*i + JOFFSET, 0, 0)
+VSX_CVT_INT_TO_FP(xvcvuxdsp, 2, uint64, float32, u64[i], f32[j], \
+ 2*i + JOFFSET, 0, 0)
+VSX_CVT_INT_TO_FP(xvcvsxwsp, 4, int32, float32, u32[j], f32[i], i, 0, 0)
+VSX_CVT_INT_TO_FP(xvcvuxwsp, 4, uint32, float32, u32[j], f32[i], i, 0, 0)
+
+/* For "use current rounding mode", define a value that will not be one of
+ * the existing rounding model enums.
+ */
+#define FLOAT_ROUND_CURRENT (float_round_nearest_even + float_round_down + \
+ float_round_up + float_round_to_zero)
+
+/* VSX_ROUND - VSX floating point round
+ * op - instruction mnemonic
+ * nels - number of elements (1, 2 or 4)
+ * tp - type (float32 or float64)
+ * fld - vsr_t field (f32 or f64)
+ * rmode - rounding mode
+ * sfprf - set FPRF
+ */
+#define VSX_ROUND(op, nels, tp, fld, rmode, sfprf) \
+void helper_##op(CPUPPCState *env, uint32_t opcode) \
+{ \
+ ppc_vsr_t xt, xb; \
+ int i; \
+ getVSR(xB(opcode), &xb, env); \
+ getVSR(xT(opcode), &xt, env); \
+ \
+ if (rmode != FLOAT_ROUND_CURRENT) { \
+ set_float_rounding_mode(rmode, &env->fp_status); \
+ } \
+ \
+ for (i = 0; i < nels; i++) { \
+ if (unlikely(tp##_is_signaling_nan(xb.fld[i]))) { \
+ fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
+ xt.fld[i] = tp##_snan_to_qnan(xb.fld[i]); \
+ } else { \
+ xt.fld[i] = tp##_round_to_int(xb.fld[i], &env->fp_status); \
+ } \
+ if (sfprf) { \
+ helper_compute_fprf(env, xt.fld[i], sfprf); \
+ } \
+ } \
+ \
+ /* If this is not a "use current rounding mode" instruction, \
+ * then inhibit setting of the XX bit and restore rounding \
+ * mode from FPSCR */ \
+ if (rmode != FLOAT_ROUND_CURRENT) { \
+ fpscr_set_rounding_mode(env); \
+ env->fp_status.float_exception_flags &= ~float_flag_inexact; \
+ } \
+ \
+ putVSR(xT(opcode), &xt, env); \
+ helper_float_check_status(env); \
+}
+
+VSX_ROUND(xsrdpi, 1, float64, f64, float_round_nearest_even, 1)
+VSX_ROUND(xsrdpic, 1, float64, f64, FLOAT_ROUND_CURRENT, 1)
+VSX_ROUND(xsrdpim, 1, float64, f64, float_round_down, 1)
+VSX_ROUND(xsrdpip, 1, float64, f64, float_round_up, 1)
+VSX_ROUND(xsrdpiz, 1, float64, f64, float_round_to_zero, 1)
+
+VSX_ROUND(xvrdpi, 2, float64, f64, float_round_nearest_even, 0)
+VSX_ROUND(xvrdpic, 2, float64, f64, FLOAT_ROUND_CURRENT, 0)
+VSX_ROUND(xvrdpim, 2, float64, f64, float_round_down, 0)
+VSX_ROUND(xvrdpip, 2, float64, f64, float_round_up, 0)
+VSX_ROUND(xvrdpiz, 2, float64, f64, float_round_to_zero, 0)
+
+VSX_ROUND(xvrspi, 4, float32, f32, float_round_nearest_even, 0)
+VSX_ROUND(xvrspic, 4, float32, f32, FLOAT_ROUND_CURRENT, 0)
+VSX_ROUND(xvrspim, 4, float32, f32, float_round_down, 0)
+VSX_ROUND(xvrspip, 4, float32, f32, float_round_up, 0)
+VSX_ROUND(xvrspiz, 4, float32, f32, float_round_to_zero, 0)
+
+uint64_t helper_xsrsp(CPUPPCState *env, uint64_t xb)
+{
+ helper_reset_fpstatus(env);
+
+ uint64_t xt = helper_frsp(env, xb);
+
+ helper_compute_fprf(env, xt, 1);
+ helper_float_check_status(env);
+ return xt;
+}
diff --git a/target-ppc/helper.h b/target-ppc/helper.h
index 6d282bb32d..99f10deee1 100644
--- a/target-ppc/helper.h
+++ b/target-ppc/helper.h
@@ -31,7 +31,11 @@ DEF_HELPER_5(lscbx, tl, env, tl, i32, i32, i32)
#if defined(TARGET_PPC64)
DEF_HELPER_3(mulldo, i64, env, i64, i64)
+DEF_HELPER_4(divdeu, i64, env, i64, i64, i32)
+DEF_HELPER_4(divde, i64, env, i64, i64, i32)
#endif
+DEF_HELPER_4(divweu, tl, env, tl, tl, i32)
+DEF_HELPER_4(divwe, tl, env, tl, tl, i32)
DEF_HELPER_FLAGS_1(cntlzw, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(popcntb, TCG_CALL_NO_RWG_SE, tl, tl)
@@ -41,6 +45,7 @@ DEF_HELPER_3(sraw, tl, env, tl, tl)
#if defined(TARGET_PPC64)
DEF_HELPER_FLAGS_1(cntlzd, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(popcntd, TCG_CALL_NO_RWG_SE, tl, tl)
+DEF_HELPER_FLAGS_2(bpermd, TCG_CALL_NO_RWG_SE, i64, i64, i64)
DEF_HELPER_3(srad, tl, env, tl, tl)
#endif
@@ -61,11 +66,18 @@ DEF_HELPER_4(fcmpo, void, env, i64, i64, i32)
DEF_HELPER_4(fcmpu, void, env, i64, i64, i32)
DEF_HELPER_2(fctiw, i64, env, i64)
+DEF_HELPER_2(fctiwu, i64, env, i64)
DEF_HELPER_2(fctiwz, i64, env, i64)
+DEF_HELPER_2(fctiwuz, i64, env, i64)
#if defined(TARGET_PPC64)
DEF_HELPER_2(fcfid, i64, env, i64)
+DEF_HELPER_2(fcfidu, i64, env, i64)
+DEF_HELPER_2(fcfids, i64, env, i64)
+DEF_HELPER_2(fcfidus, i64, env, i64)
DEF_HELPER_2(fctid, i64, env, i64)
+DEF_HELPER_2(fctidu, i64, env, i64)
DEF_HELPER_2(fctidz, i64, env, i64)
+DEF_HELPER_2(fctiduz, i64, env, i64)
#endif
DEF_HELPER_2(frsp, i64, env, i64)
DEF_HELPER_2(frin, i64, env, i64)
@@ -87,6 +99,9 @@ DEF_HELPER_2(fres, i64, env, i64)
DEF_HELPER_2(frsqrte, i64, env, i64)
DEF_HELPER_4(fsel, i64, env, i64, i64, i64)
+DEF_HELPER_FLAGS_2(ftdiv, TCG_CALL_NO_RWG_SE, i32, i64, i64)
+DEF_HELPER_FLAGS_1(ftsqrt, TCG_CALL_NO_RWG_SE, i32, i64)
+
#define dh_alias_avr ptr
#define dh_ctype_avr ppc_avr_t *
#define dh_is_signed_avr dh_is_signed_ptr
@@ -94,9 +109,11 @@ DEF_HELPER_4(fsel, i64, env, i64, i64, i64)
DEF_HELPER_3(vaddubm, void, avr, avr, avr)
DEF_HELPER_3(vadduhm, void, avr, avr, avr)
DEF_HELPER_3(vadduwm, void, avr, avr, avr)
+DEF_HELPER_3(vaddudm, void, avr, avr, avr)
DEF_HELPER_3(vsububm, void, avr, avr, avr)
DEF_HELPER_3(vsubuhm, void, avr, avr, avr)
DEF_HELPER_3(vsubuwm, void, avr, avr, avr)
+DEF_HELPER_3(vsubudm, void, avr, avr, avr)
DEF_HELPER_3(vavgub, void, avr, avr, avr)
DEF_HELPER_3(vavguh, void, avr, avr, avr)
DEF_HELPER_3(vavguw, void, avr, avr, avr)
@@ -106,24 +123,31 @@ DEF_HELPER_3(vavgsw, void, avr, avr, avr)
DEF_HELPER_3(vminsb, void, avr, avr, avr)
DEF_HELPER_3(vminsh, void, avr, avr, avr)
DEF_HELPER_3(vminsw, void, avr, avr, avr)
+DEF_HELPER_3(vminsd, void, avr, avr, avr)
DEF_HELPER_3(vmaxsb, void, avr, avr, avr)
DEF_HELPER_3(vmaxsh, void, avr, avr, avr)
DEF_HELPER_3(vmaxsw, void, avr, avr, avr)
+DEF_HELPER_3(vmaxsd, void, avr, avr, avr)
DEF_HELPER_3(vminub, void, avr, avr, avr)
DEF_HELPER_3(vminuh, void, avr, avr, avr)
DEF_HELPER_3(vminuw, void, avr, avr, avr)
+DEF_HELPER_3(vminud, void, avr, avr, avr)
DEF_HELPER_3(vmaxub, void, avr, avr, avr)
DEF_HELPER_3(vmaxuh, void, avr, avr, avr)
DEF_HELPER_3(vmaxuw, void, avr, avr, avr)
+DEF_HELPER_3(vmaxud, void, avr, avr, avr)
DEF_HELPER_4(vcmpequb, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpequh, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpequw, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpequd, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpgtub, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpgtuh, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpgtuw, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpgtud, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpgtsb, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpgtsh, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpgtsw, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpgtsd, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpeqfp, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpgefp, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpgtfp, void, env, avr, avr, avr)
@@ -131,12 +155,15 @@ DEF_HELPER_4(vcmpbfp, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpequb_dot, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpequh_dot, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpequw_dot, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpequd_dot, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpgtub_dot, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpgtuh_dot, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpgtuw_dot, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpgtud_dot, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpgtsb_dot, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpgtsh_dot, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpgtsw_dot, void, env, avr, avr, avr)
+DEF_HELPER_4(vcmpgtsd_dot, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpeqfp_dot, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpgefp_dot, void, env, avr, avr, avr)
DEF_HELPER_4(vcmpgtfp_dot, void, env, avr, avr, avr)
@@ -149,21 +176,29 @@ DEF_HELPER_3(vmrghh, void, avr, avr, avr)
DEF_HELPER_3(vmrghw, void, avr, avr, avr)
DEF_HELPER_3(vmulesb, void, avr, avr, avr)
DEF_HELPER_3(vmulesh, void, avr, avr, avr)
+DEF_HELPER_3(vmulesw, void, avr, avr, avr)
DEF_HELPER_3(vmuleub, void, avr, avr, avr)
DEF_HELPER_3(vmuleuh, void, avr, avr, avr)
+DEF_HELPER_3(vmuleuw, void, avr, avr, avr)
DEF_HELPER_3(vmulosb, void, avr, avr, avr)
DEF_HELPER_3(vmulosh, void, avr, avr, avr)
+DEF_HELPER_3(vmulosw, void, avr, avr, avr)
DEF_HELPER_3(vmuloub, void, avr, avr, avr)
DEF_HELPER_3(vmulouh, void, avr, avr, avr)
+DEF_HELPER_3(vmulouw, void, avr, avr, avr)
+DEF_HELPER_3(vmuluwm, void, avr, avr, avr)
DEF_HELPER_3(vsrab, void, avr, avr, avr)
DEF_HELPER_3(vsrah, void, avr, avr, avr)
DEF_HELPER_3(vsraw, void, avr, avr, avr)
+DEF_HELPER_3(vsrad, void, avr, avr, avr)
DEF_HELPER_3(vsrb, void, avr, avr, avr)
DEF_HELPER_3(vsrh, void, avr, avr, avr)
DEF_HELPER_3(vsrw, void, avr, avr, avr)
+DEF_HELPER_3(vsrd, void, avr, avr, avr)
DEF_HELPER_3(vslb, void, avr, avr, avr)
DEF_HELPER_3(vslh, void, avr, avr, avr)
DEF_HELPER_3(vslw, void, avr, avr, avr)
+DEF_HELPER_3(vsld, void, avr, avr, avr)
DEF_HELPER_3(vslo, void, avr, avr, avr)
DEF_HELPER_3(vsro, void, avr, avr, avr)
DEF_HELPER_3(vaddcuw, void, avr, avr, avr)
@@ -182,9 +217,18 @@ DEF_HELPER_4(vadduws, void, env, avr, avr, avr)
DEF_HELPER_4(vsububs, void, env, avr, avr, avr)
DEF_HELPER_4(vsubuhs, void, env, avr, avr, avr)
DEF_HELPER_4(vsubuws, void, env, avr, avr, avr)
+DEF_HELPER_3(vadduqm, void, avr, avr, avr)
+DEF_HELPER_4(vaddecuq, void, avr, avr, avr, avr)
+DEF_HELPER_4(vaddeuqm, void, avr, avr, avr, avr)
+DEF_HELPER_3(vaddcuq, void, avr, avr, avr)
+DEF_HELPER_3(vsubuqm, void, avr, avr, avr)
+DEF_HELPER_4(vsubecuq, void, avr, avr, avr, avr)
+DEF_HELPER_4(vsubeuqm, void, avr, avr, avr, avr)
+DEF_HELPER_3(vsubcuq, void, avr, avr, avr)
DEF_HELPER_3(vrlb, void, avr, avr, avr)
DEF_HELPER_3(vrlh, void, avr, avr, avr)
DEF_HELPER_3(vrlw, void, avr, avr, avr)
+DEF_HELPER_3(vrld, void, avr, avr, avr)
DEF_HELPER_3(vsl, void, avr, avr, avr)
DEF_HELPER_3(vsr, void, avr, avr, avr)
DEF_HELPER_4(vsldoi, void, avr, avr, avr, i32)
@@ -198,8 +242,10 @@ DEF_HELPER_2(vupkhpx, void, avr, avr)
DEF_HELPER_2(vupklpx, void, avr, avr)
DEF_HELPER_2(vupkhsb, void, avr, avr)
DEF_HELPER_2(vupkhsh, void, avr, avr)
+DEF_HELPER_2(vupkhsw, void, avr, avr)
DEF_HELPER_2(vupklsb, void, avr, avr)
DEF_HELPER_2(vupklsh, void, avr, avr)
+DEF_HELPER_2(vupklsw, void, avr, avr)
DEF_HELPER_5(vmsumubm, void, env, avr, avr, avr, avr)
DEF_HELPER_5(vmsummbm, void, env, avr, avr, avr, avr)
DEF_HELPER_5(vsel, void, env, avr, avr, avr, avr)
@@ -208,10 +254,14 @@ DEF_HELPER_4(vpkshss, void, env, avr, avr, avr)
DEF_HELPER_4(vpkshus, void, env, avr, avr, avr)
DEF_HELPER_4(vpkswss, void, env, avr, avr, avr)
DEF_HELPER_4(vpkswus, void, env, avr, avr, avr)
+DEF_HELPER_4(vpksdss, void, env, avr, avr, avr)
+DEF_HELPER_4(vpksdus, void, env, avr, avr, avr)
DEF_HELPER_4(vpkuhus, void, env, avr, avr, avr)
DEF_HELPER_4(vpkuwus, void, env, avr, avr, avr)
+DEF_HELPER_4(vpkudus, void, env, avr, avr, avr)
DEF_HELPER_4(vpkuhum, void, env, avr, avr, avr)
DEF_HELPER_4(vpkuwum, void, env, avr, avr, avr)
+DEF_HELPER_4(vpkudum, void, env, avr, avr, avr)
DEF_HELPER_3(vpkpx, void, avr, avr, avr)
DEF_HELPER_5(vmhaddshs, void, env, avr, avr, avr, avr)
DEF_HELPER_5(vmhraddshs, void, env, avr, avr, avr, avr)
@@ -251,6 +301,163 @@ DEF_HELPER_4(vcfsx, void, env, avr, avr, i32)
DEF_HELPER_4(vctuxs, void, env, avr, avr, i32)
DEF_HELPER_4(vctsxs, void, env, avr, avr, i32)
+DEF_HELPER_2(vclzb, void, avr, avr)
+DEF_HELPER_2(vclzh, void, avr, avr)
+DEF_HELPER_2(vclzw, void, avr, avr)
+DEF_HELPER_2(vclzd, void, avr, avr)
+DEF_HELPER_2(vpopcntb, void, avr, avr)
+DEF_HELPER_2(vpopcnth, void, avr, avr)
+DEF_HELPER_2(vpopcntw, void, avr, avr)
+DEF_HELPER_2(vpopcntd, void, avr, avr)
+DEF_HELPER_3(vbpermq, void, avr, avr, avr)
+DEF_HELPER_2(vgbbd, void, avr, avr)
+DEF_HELPER_3(vpmsumb, void, avr, avr, avr)
+DEF_HELPER_3(vpmsumh, void, avr, avr, avr)
+DEF_HELPER_3(vpmsumw, void, avr, avr, avr)
+DEF_HELPER_3(vpmsumd, void, avr, avr, avr)
+
+DEF_HELPER_2(vsbox, void, avr, avr)
+DEF_HELPER_3(vcipher, void, avr, avr, avr)
+DEF_HELPER_3(vcipherlast, void, avr, avr, avr)
+DEF_HELPER_3(vncipher, void, avr, avr, avr)
+DEF_HELPER_3(vncipherlast, void, avr, avr, avr)
+DEF_HELPER_3(vshasigmaw, void, avr, avr, i32)
+DEF_HELPER_3(vshasigmad, void, avr, avr, i32)
+DEF_HELPER_4(vpermxor, void, avr, avr, avr, avr)
+
+DEF_HELPER_4(bcdadd, i32, avr, avr, avr, i32)
+DEF_HELPER_4(bcdsub, i32, avr, avr, avr, i32)
+
+DEF_HELPER_2(xsadddp, void, env, i32)
+DEF_HELPER_2(xssubdp, void, env, i32)
+DEF_HELPER_2(xsmuldp, void, env, i32)
+DEF_HELPER_2(xsdivdp, void, env, i32)
+DEF_HELPER_2(xsredp, void, env, i32)
+DEF_HELPER_2(xssqrtdp, void, env, i32)
+DEF_HELPER_2(xsrsqrtedp, void, env, i32)
+DEF_HELPER_2(xstdivdp, void, env, i32)
+DEF_HELPER_2(xstsqrtdp, void, env, i32)
+DEF_HELPER_2(xsmaddadp, void, env, i32)
+DEF_HELPER_2(xsmaddmdp, void, env, i32)
+DEF_HELPER_2(xsmsubadp, void, env, i32)
+DEF_HELPER_2(xsmsubmdp, void, env, i32)
+DEF_HELPER_2(xsnmaddadp, void, env, i32)
+DEF_HELPER_2(xsnmaddmdp, void, env, i32)
+DEF_HELPER_2(xsnmsubadp, void, env, i32)
+DEF_HELPER_2(xsnmsubmdp, void, env, i32)
+DEF_HELPER_2(xscmpodp, void, env, i32)
+DEF_HELPER_2(xscmpudp, void, env, i32)
+DEF_HELPER_2(xsmaxdp, void, env, i32)
+DEF_HELPER_2(xsmindp, void, env, i32)
+DEF_HELPER_2(xscvdpsp, void, env, i32)
+DEF_HELPER_2(xscvdpspn, i64, env, i64)
+DEF_HELPER_2(xscvspdp, void, env, i32)
+DEF_HELPER_2(xscvspdpn, i64, env, i64)
+DEF_HELPER_2(xscvdpsxds, void, env, i32)
+DEF_HELPER_2(xscvdpsxws, void, env, i32)
+DEF_HELPER_2(xscvdpuxds, void, env, i32)
+DEF_HELPER_2(xscvdpuxws, void, env, i32)
+DEF_HELPER_2(xscvsxddp, void, env, i32)
+DEF_HELPER_2(xscvuxdsp, void, env, i32)
+DEF_HELPER_2(xscvsxdsp, void, env, i32)
+DEF_HELPER_2(xscvuxddp, void, env, i32)
+DEF_HELPER_2(xsrdpi, void, env, i32)
+DEF_HELPER_2(xsrdpic, void, env, i32)
+DEF_HELPER_2(xsrdpim, void, env, i32)
+DEF_HELPER_2(xsrdpip, void, env, i32)
+DEF_HELPER_2(xsrdpiz, void, env, i32)
+
+DEF_HELPER_2(xsaddsp, void, env, i32)
+DEF_HELPER_2(xssubsp, void, env, i32)
+DEF_HELPER_2(xsmulsp, void, env, i32)
+DEF_HELPER_2(xsdivsp, void, env, i32)
+DEF_HELPER_2(xsresp, void, env, i32)
+DEF_HELPER_2(xsrsp, i64, env, i64)
+DEF_HELPER_2(xssqrtsp, void, env, i32)
+DEF_HELPER_2(xsrsqrtesp, void, env, i32)
+DEF_HELPER_2(xsmaddasp, void, env, i32)
+DEF_HELPER_2(xsmaddmsp, void, env, i32)
+DEF_HELPER_2(xsmsubasp, void, env, i32)
+DEF_HELPER_2(xsmsubmsp, void, env, i32)
+DEF_HELPER_2(xsnmaddasp, void, env, i32)
+DEF_HELPER_2(xsnmaddmsp, void, env, i32)
+DEF_HELPER_2(xsnmsubasp, void, env, i32)
+DEF_HELPER_2(xsnmsubmsp, void, env, i32)
+
+DEF_HELPER_2(xvadddp, void, env, i32)
+DEF_HELPER_2(xvsubdp, void, env, i32)
+DEF_HELPER_2(xvmuldp, void, env, i32)
+DEF_HELPER_2(xvdivdp, void, env, i32)
+DEF_HELPER_2(xvredp, void, env, i32)
+DEF_HELPER_2(xvsqrtdp, void, env, i32)
+DEF_HELPER_2(xvrsqrtedp, void, env, i32)
+DEF_HELPER_2(xvtdivdp, void, env, i32)
+DEF_HELPER_2(xvtsqrtdp, void, env, i32)
+DEF_HELPER_2(xvmaddadp, void, env, i32)
+DEF_HELPER_2(xvmaddmdp, void, env, i32)
+DEF_HELPER_2(xvmsubadp, void, env, i32)
+DEF_HELPER_2(xvmsubmdp, void, env, i32)
+DEF_HELPER_2(xvnmaddadp, void, env, i32)
+DEF_HELPER_2(xvnmaddmdp, void, env, i32)
+DEF_HELPER_2(xvnmsubadp, void, env, i32)
+DEF_HELPER_2(xvnmsubmdp, void, env, i32)
+DEF_HELPER_2(xvmaxdp, void, env, i32)
+DEF_HELPER_2(xvmindp, void, env, i32)
+DEF_HELPER_2(xvcmpeqdp, void, env, i32)
+DEF_HELPER_2(xvcmpgedp, void, env, i32)
+DEF_HELPER_2(xvcmpgtdp, void, env, i32)
+DEF_HELPER_2(xvcvdpsp, void, env, i32)
+DEF_HELPER_2(xvcvdpsxds, void, env, i32)
+DEF_HELPER_2(xvcvdpsxws, void, env, i32)
+DEF_HELPER_2(xvcvdpuxds, void, env, i32)
+DEF_HELPER_2(xvcvdpuxws, void, env, i32)
+DEF_HELPER_2(xvcvsxddp, void, env, i32)
+DEF_HELPER_2(xvcvuxddp, void, env, i32)
+DEF_HELPER_2(xvcvsxwdp, void, env, i32)
+DEF_HELPER_2(xvcvuxwdp, void, env, i32)
+DEF_HELPER_2(xvrdpi, void, env, i32)
+DEF_HELPER_2(xvrdpic, void, env, i32)
+DEF_HELPER_2(xvrdpim, void, env, i32)
+DEF_HELPER_2(xvrdpip, void, env, i32)
+DEF_HELPER_2(xvrdpiz, void, env, i32)
+
+DEF_HELPER_2(xvaddsp, void, env, i32)
+DEF_HELPER_2(xvsubsp, void, env, i32)
+DEF_HELPER_2(xvmulsp, void, env, i32)
+DEF_HELPER_2(xvdivsp, void, env, i32)
+DEF_HELPER_2(xvresp, void, env, i32)
+DEF_HELPER_2(xvsqrtsp, void, env, i32)
+DEF_HELPER_2(xvrsqrtesp, void, env, i32)
+DEF_HELPER_2(xvtdivsp, void, env, i32)
+DEF_HELPER_2(xvtsqrtsp, void, env, i32)
+DEF_HELPER_2(xvmaddasp, void, env, i32)
+DEF_HELPER_2(xvmaddmsp, void, env, i32)
+DEF_HELPER_2(xvmsubasp, void, env, i32)
+DEF_HELPER_2(xvmsubmsp, void, env, i32)
+DEF_HELPER_2(xvnmaddasp, void, env, i32)
+DEF_HELPER_2(xvnmaddmsp, void, env, i32)
+DEF_HELPER_2(xvnmsubasp, void, env, i32)
+DEF_HELPER_2(xvnmsubmsp, void, env, i32)
+DEF_HELPER_2(xvmaxsp, void, env, i32)
+DEF_HELPER_2(xvminsp, void, env, i32)
+DEF_HELPER_2(xvcmpeqsp, void, env, i32)
+DEF_HELPER_2(xvcmpgesp, void, env, i32)
+DEF_HELPER_2(xvcmpgtsp, void, env, i32)
+DEF_HELPER_2(xvcvspdp, void, env, i32)
+DEF_HELPER_2(xvcvspsxds, void, env, i32)
+DEF_HELPER_2(xvcvspsxws, void, env, i32)
+DEF_HELPER_2(xvcvspuxds, void, env, i32)
+DEF_HELPER_2(xvcvspuxws, void, env, i32)
+DEF_HELPER_2(xvcvsxdsp, void, env, i32)
+DEF_HELPER_2(xvcvuxdsp, void, env, i32)
+DEF_HELPER_2(xvcvsxwsp, void, env, i32)
+DEF_HELPER_2(xvcvuxwsp, void, env, i32)
+DEF_HELPER_2(xvrspi, void, env, i32)
+DEF_HELPER_2(xvrspic, void, env, i32)
+DEF_HELPER_2(xvrspim, void, env, i32)
+DEF_HELPER_2(xvrspip, void, env, i32)
+DEF_HELPER_2(xvrspiz, void, env, i32)
+
DEF_HELPER_2(efscfsi, i32, env, i32)
DEF_HELPER_2(efscfui, i32, env, i32)
DEF_HELPER_2(efscfuf, i32, env, i32)
diff --git a/target-ppc/int_helper.c b/target-ppc/int_helper.c
index e50bdd20ec..63dde94b04 100644
--- a/target-ppc/int_helper.c
+++ b/target-ppc/int_helper.c
@@ -41,6 +41,119 @@ uint64_t helper_mulldo(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
}
#endif
+target_ulong helper_divweu(CPUPPCState *env, target_ulong ra, target_ulong rb,
+ uint32_t oe)
+{
+ uint64_t rt = 0;
+ int overflow = 0;
+
+ uint64_t dividend = (uint64_t)ra << 32;
+ uint64_t divisor = (uint32_t)rb;
+
+ if (unlikely(divisor == 0)) {
+ overflow = 1;
+ } else {
+ rt = dividend / divisor;
+ overflow = rt > UINT32_MAX;
+ }
+
+ if (unlikely(overflow)) {
+ rt = 0; /* Undefined */
+ }
+
+ if (oe) {
+ if (unlikely(overflow)) {
+ env->so = env->ov = 1;
+ } else {
+ env->ov = 0;
+ }
+ }
+
+ return (target_ulong)rt;
+}
+
+target_ulong helper_divwe(CPUPPCState *env, target_ulong ra, target_ulong rb,
+ uint32_t oe)
+{
+ int64_t rt = 0;
+ int overflow = 0;
+
+ int64_t dividend = (int64_t)ra << 32;
+ int64_t divisor = (int64_t)((int32_t)rb);
+
+ if (unlikely((divisor == 0) ||
+ ((divisor == -1ull) && (dividend == INT64_MIN)))) {
+ overflow = 1;
+ } else {
+ rt = dividend / divisor;
+ overflow = rt != (int32_t)rt;
+ }
+
+ if (unlikely(overflow)) {
+ rt = 0; /* Undefined */
+ }
+
+ if (oe) {
+ if (unlikely(overflow)) {
+ env->so = env->ov = 1;
+ } else {
+ env->ov = 0;
+ }
+ }
+
+ return (target_ulong)rt;
+}
+
+#if defined(TARGET_PPC64)
+
+uint64_t helper_divdeu(CPUPPCState *env, uint64_t ra, uint64_t rb, uint32_t oe)
+{
+ uint64_t rt = 0;
+ int overflow = 0;
+
+ overflow = divu128(&rt, &ra, rb);
+
+ if (unlikely(overflow)) {
+ rt = 0; /* Undefined */
+ }
+
+ if (oe) {
+ if (unlikely(overflow)) {
+ env->so = env->ov = 1;
+ } else {
+ env->ov = 0;
+ }
+ }
+
+ return rt;
+}
+
+uint64_t helper_divde(CPUPPCState *env, uint64_t rau, uint64_t rbu, uint32_t oe)
+{
+ int64_t rt = 0;
+ int64_t ra = (int64_t)rau;
+ int64_t rb = (int64_t)rbu;
+ int overflow = divs128(&rt, &ra, rb);
+
+ if (unlikely(overflow)) {
+ rt = 0; /* Undefined */
+ }
+
+ if (oe) {
+
+ if (unlikely(overflow)) {
+ env->so = env->ov = 1;
+ } else {
+ env->ov = 0;
+ }
+ }
+
+ return rt;
+}
+
+#endif
+
+
target_ulong helper_cntlzw(target_ulong t)
{
return clz32(t);
@@ -53,6 +166,26 @@ target_ulong helper_cntlzd(target_ulong t)
}
#endif
+#if defined(TARGET_PPC64)
+
+uint64_t helper_bpermd(uint64_t rs, uint64_t rb)
+{
+ int i;
+ uint64_t ra = 0;
+
+ for (i = 0; i < 8; i++) {
+ int index = (rs >> (i*8)) & 0xFF;
+ if (index < 64) {
+ if (rb & (1ull << (63-index))) {
+ ra |= 1 << i;
+ }
+ }
+ }
+ return ra;
+}
+
+#endif
+
target_ulong helper_cmpb(target_ulong rs, target_ulong rb)
{
target_ulong mask = 0xff;
@@ -371,6 +504,8 @@ void helper_vaddcuw(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
VARITH(ubm, u8)
VARITH(uhm, u16)
VARITH(uwm, u32)
+VARITH(udm, u64)
+VARITH_DO(muluwm, *, u32)
#undef VARITH_DO
#undef VARITH
@@ -491,15 +626,18 @@ VCF(sx, int32_to_float32, s32)
void helper_vcmp##suffix(CPUPPCState *env, ppc_avr_t *r, \
ppc_avr_t *a, ppc_avr_t *b) \
{ \
- uint32_t ones = (uint32_t)-1; \
- uint32_t all = ones; \
- uint32_t none = 0; \
+ uint64_t ones = (uint64_t)-1; \
+ uint64_t all = ones; \
+ uint64_t none = 0; \
int i; \
\
for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
- uint32_t result = (a->element[i] compare b->element[i] ? \
+ uint64_t result = (a->element[i] compare b->element[i] ? \
ones : 0x0); \
switch (sizeof(a->element[0])) { \
+ case 8: \
+ r->u64[i] = result; \
+ break; \
case 4: \
r->u32[i] = result; \
break; \
@@ -523,12 +661,15 @@ VCF(sx, int32_to_float32, s32)
VCMP(equb, ==, u8)
VCMP(equh, ==, u16)
VCMP(equw, ==, u32)
+VCMP(equd, ==, u64)
VCMP(gtub, >, u8)
VCMP(gtuh, >, u16)
VCMP(gtuw, >, u32)
+VCMP(gtud, >, u64)
VCMP(gtsb, >, s8)
VCMP(gtsh, >, s16)
VCMP(gtsw, >, s32)
+VCMP(gtsd, >, s64)
#undef VCMP_DO
#undef VCMP
@@ -689,9 +830,11 @@ void helper_vmhraddshs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
VMINMAX(sb, s8)
VMINMAX(sh, s16)
VMINMAX(sw, s32)
+VMINMAX(sd, s64)
VMINMAX(ub, u8)
VMINMAX(uh, u16)
VMINMAX(uw, u32)
+VMINMAX(ud, u64)
#undef VMINMAX_DO
#undef VMINMAX
@@ -849,28 +992,32 @@ void helper_vmsumuhs(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a,
}
}
-#define VMUL_DO(name, mul_element, prod_element, evenp) \
+#define VMUL_DO(name, mul_element, prod_element, cast, evenp) \
void helper_v##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
{ \
int i; \
\
VECTOR_FOR_INORDER_I(i, prod_element) { \
if (evenp) { \
- r->prod_element[i] = a->mul_element[i * 2 + HI_IDX] * \
- b->mul_element[i * 2 + HI_IDX]; \
+ r->prod_element[i] = \
+ (cast)a->mul_element[i * 2 + HI_IDX] * \
+ (cast)b->mul_element[i * 2 + HI_IDX]; \
} else { \
- r->prod_element[i] = a->mul_element[i * 2 + LO_IDX] * \
- b->mul_element[i * 2 + LO_IDX]; \
+ r->prod_element[i] = \
+ (cast)a->mul_element[i * 2 + LO_IDX] * \
+ (cast)b->mul_element[i * 2 + LO_IDX]; \
} \
} \
}
-#define VMUL(suffix, mul_element, prod_element) \
- VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
- VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
-VMUL(sb, s8, s16)
-VMUL(sh, s16, s32)
-VMUL(ub, u8, u16)
-VMUL(uh, u16, u32)
+#define VMUL(suffix, mul_element, prod_element, cast) \
+ VMUL_DO(mule##suffix, mul_element, prod_element, cast, 1) \
+ VMUL_DO(mulo##suffix, mul_element, prod_element, cast, 0)
+VMUL(sb, s8, s16, int16_t)
+VMUL(sh, s16, s32, int32_t)
+VMUL(sw, s32, s64, int64_t)
+VMUL(ub, u8, u16, uint16_t)
+VMUL(uh, u16, u32, uint32_t)
+VMUL(uw, u32, u64, uint64_t)
#undef VMUL_DO
#undef VMUL
@@ -898,6 +1045,383 @@ void helper_vperm(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
}
#if defined(HOST_WORDS_BIGENDIAN)
+#define VBPERMQ_INDEX(avr, i) ((avr)->u8[(i)])
+#define VBPERMQ_DW(index) (((index) & 0x40) != 0)
+#else
+#define VBPERMQ_INDEX(avr, i) ((avr)->u8[15-(i)])
+#define VBPERMQ_DW(index) (((index) & 0x40) == 0)
+#endif
+
+void helper_vbpermq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+ int i;
+ uint64_t perm = 0;
+
+ VECTOR_FOR_INORDER_I(i, u8) {
+ int index = VBPERMQ_INDEX(b, i);
+
+ if (index < 128) {
+ uint64_t mask = (1ull << (63-(index & 0x3F)));
+ if (a->u64[VBPERMQ_DW(index)] & mask) {
+ perm |= (0x8000 >> i);
+ }
+ }
+ }
+
+ r->u64[HI_IDX] = perm;
+ r->u64[LO_IDX] = 0;
+}
+
+#undef VBPERMQ_INDEX
+#undef VBPERMQ_DW
+
+uint64_t VGBBD_MASKS[256] = {
+ 0x0000000000000000ull, /* 00 */
+ 0x0000000000000080ull, /* 01 */
+ 0x0000000000008000ull, /* 02 */
+ 0x0000000000008080ull, /* 03 */
+ 0x0000000000800000ull, /* 04 */
+ 0x0000000000800080ull, /* 05 */
+ 0x0000000000808000ull, /* 06 */
+ 0x0000000000808080ull, /* 07 */
+ 0x0000000080000000ull, /* 08 */
+ 0x0000000080000080ull, /* 09 */
+ 0x0000000080008000ull, /* 0A */
+ 0x0000000080008080ull, /* 0B */
+ 0x0000000080800000ull, /* 0C */
+ 0x0000000080800080ull, /* 0D */
+ 0x0000000080808000ull, /* 0E */
+ 0x0000000080808080ull, /* 0F */
+ 0x0000008000000000ull, /* 10 */
+ 0x0000008000000080ull, /* 11 */
+ 0x0000008000008000ull, /* 12 */
+ 0x0000008000008080ull, /* 13 */
+ 0x0000008000800000ull, /* 14 */
+ 0x0000008000800080ull, /* 15 */
+ 0x0000008000808000ull, /* 16 */
+ 0x0000008000808080ull, /* 17 */
+ 0x0000008080000000ull, /* 18 */
+ 0x0000008080000080ull, /* 19 */
+ 0x0000008080008000ull, /* 1A */
+ 0x0000008080008080ull, /* 1B */
+ 0x0000008080800000ull, /* 1C */
+ 0x0000008080800080ull, /* 1D */
+ 0x0000008080808000ull, /* 1E */
+ 0x0000008080808080ull, /* 1F */
+ 0x0000800000000000ull, /* 20 */
+ 0x0000800000000080ull, /* 21 */
+ 0x0000800000008000ull, /* 22 */
+ 0x0000800000008080ull, /* 23 */
+ 0x0000800000800000ull, /* 24 */
+ 0x0000800000800080ull, /* 25 */
+ 0x0000800000808000ull, /* 26 */
+ 0x0000800000808080ull, /* 27 */
+ 0x0000800080000000ull, /* 28 */
+ 0x0000800080000080ull, /* 29 */
+ 0x0000800080008000ull, /* 2A */
+ 0x0000800080008080ull, /* 2B */
+ 0x0000800080800000ull, /* 2C */
+ 0x0000800080800080ull, /* 2D */
+ 0x0000800080808000ull, /* 2E */
+ 0x0000800080808080ull, /* 2F */
+ 0x0000808000000000ull, /* 30 */
+ 0x0000808000000080ull, /* 31 */
+ 0x0000808000008000ull, /* 32 */
+ 0x0000808000008080ull, /* 33 */
+ 0x0000808000800000ull, /* 34 */
+ 0x0000808000800080ull, /* 35 */
+ 0x0000808000808000ull, /* 36 */
+ 0x0000808000808080ull, /* 37 */
+ 0x0000808080000000ull, /* 38 */
+ 0x0000808080000080ull, /* 39 */
+ 0x0000808080008000ull, /* 3A */
+ 0x0000808080008080ull, /* 3B */
+ 0x0000808080800000ull, /* 3C */
+ 0x0000808080800080ull, /* 3D */
+ 0x0000808080808000ull, /* 3E */
+ 0x0000808080808080ull, /* 3F */
+ 0x0080000000000000ull, /* 40 */
+ 0x0080000000000080ull, /* 41 */
+ 0x0080000000008000ull, /* 42 */
+ 0x0080000000008080ull, /* 43 */
+ 0x0080000000800000ull, /* 44 */
+ 0x0080000000800080ull, /* 45 */
+ 0x0080000000808000ull, /* 46 */
+ 0x0080000000808080ull, /* 47 */
+ 0x0080000080000000ull, /* 48 */
+ 0x0080000080000080ull, /* 49 */
+ 0x0080000080008000ull, /* 4A */
+ 0x0080000080008080ull, /* 4B */
+ 0x0080000080800000ull, /* 4C */
+ 0x0080000080800080ull, /* 4D */
+ 0x0080000080808000ull, /* 4E */
+ 0x0080000080808080ull, /* 4F */
+ 0x0080008000000000ull, /* 50 */
+ 0x0080008000000080ull, /* 51 */
+ 0x0080008000008000ull, /* 52 */
+ 0x0080008000008080ull, /* 53 */
+ 0x0080008000800000ull, /* 54 */
+ 0x0080008000800080ull, /* 55 */
+ 0x0080008000808000ull, /* 56 */
+ 0x0080008000808080ull, /* 57 */
+ 0x0080008080000000ull, /* 58 */
+ 0x0080008080000080ull, /* 59 */
+ 0x0080008080008000ull, /* 5A */
+ 0x0080008080008080ull, /* 5B */
+ 0x0080008080800000ull, /* 5C */
+ 0x0080008080800080ull, /* 5D */
+ 0x0080008080808000ull, /* 5E */
+ 0x0080008080808080ull, /* 5F */
+ 0x0080800000000000ull, /* 60 */
+ 0x0080800000000080ull, /* 61 */
+ 0x0080800000008000ull, /* 62 */
+ 0x0080800000008080ull, /* 63 */
+ 0x0080800000800000ull, /* 64 */
+ 0x0080800000800080ull, /* 65 */
+ 0x0080800000808000ull, /* 66 */
+ 0x0080800000808080ull, /* 67 */
+ 0x0080800080000000ull, /* 68 */
+ 0x0080800080000080ull, /* 69 */
+ 0x0080800080008000ull, /* 6A */
+ 0x0080800080008080ull, /* 6B */
+ 0x0080800080800000ull, /* 6C */
+ 0x0080800080800080ull, /* 6D */
+ 0x0080800080808000ull, /* 6E */
+ 0x0080800080808080ull, /* 6F */
+ 0x0080808000000000ull, /* 70 */
+ 0x0080808000000080ull, /* 71 */
+ 0x0080808000008000ull, /* 72 */
+ 0x0080808000008080ull, /* 73 */
+ 0x0080808000800000ull, /* 74 */
+ 0x0080808000800080ull, /* 75 */
+ 0x0080808000808000ull, /* 76 */
+ 0x0080808000808080ull, /* 77 */
+ 0x0080808080000000ull, /* 78 */
+ 0x0080808080000080ull, /* 79 */
+ 0x0080808080008000ull, /* 7A */
+ 0x0080808080008080ull, /* 7B */
+ 0x0080808080800000ull, /* 7C */
+ 0x0080808080800080ull, /* 7D */
+ 0x0080808080808000ull, /* 7E */
+ 0x0080808080808080ull, /* 7F */
+ 0x8000000000000000ull, /* 80 */
+ 0x8000000000000080ull, /* 81 */
+ 0x8000000000008000ull, /* 82 */
+ 0x8000000000008080ull, /* 83 */
+ 0x8000000000800000ull, /* 84 */
+ 0x8000000000800080ull, /* 85 */
+ 0x8000000000808000ull, /* 86 */
+ 0x8000000000808080ull, /* 87 */
+ 0x8000000080000000ull, /* 88 */
+ 0x8000000080000080ull, /* 89 */
+ 0x8000000080008000ull, /* 8A */
+ 0x8000000080008080ull, /* 8B */
+ 0x8000000080800000ull, /* 8C */
+ 0x8000000080800080ull, /* 8D */
+ 0x8000000080808000ull, /* 8E */
+ 0x8000000080808080ull, /* 8F */
+ 0x8000008000000000ull, /* 90 */
+ 0x8000008000000080ull, /* 91 */
+ 0x8000008000008000ull, /* 92 */
+ 0x8000008000008080ull, /* 93 */
+ 0x8000008000800000ull, /* 94 */
+ 0x8000008000800080ull, /* 95 */
+ 0x8000008000808000ull, /* 96 */
+ 0x8000008000808080ull, /* 97 */
+ 0x8000008080000000ull, /* 98 */
+ 0x8000008080000080ull, /* 99 */
+ 0x8000008080008000ull, /* 9A */
+ 0x8000008080008080ull, /* 9B */
+ 0x8000008080800000ull, /* 9C */
+ 0x8000008080800080ull, /* 9D */
+ 0x8000008080808000ull, /* 9E */
+ 0x8000008080808080ull, /* 9F */
+ 0x8000800000000000ull, /* A0 */
+ 0x8000800000000080ull, /* A1 */
+ 0x8000800000008000ull, /* A2 */
+ 0x8000800000008080ull, /* A3 */
+ 0x8000800000800000ull, /* A4 */
+ 0x8000800000800080ull, /* A5 */
+ 0x8000800000808000ull, /* A6 */
+ 0x8000800000808080ull, /* A7 */
+ 0x8000800080000000ull, /* A8 */
+ 0x8000800080000080ull, /* A9 */
+ 0x8000800080008000ull, /* AA */
+ 0x8000800080008080ull, /* AB */
+ 0x8000800080800000ull, /* AC */
+ 0x8000800080800080ull, /* AD */
+ 0x8000800080808000ull, /* AE */
+ 0x8000800080808080ull, /* AF */
+ 0x8000808000000000ull, /* B0 */
+ 0x8000808000000080ull, /* B1 */
+ 0x8000808000008000ull, /* B2 */
+ 0x8000808000008080ull, /* B3 */
+ 0x8000808000800000ull, /* B4 */
+ 0x8000808000800080ull, /* B5 */
+ 0x8000808000808000ull, /* B6 */
+ 0x8000808000808080ull, /* B7 */
+ 0x8000808080000000ull, /* B8 */
+ 0x8000808080000080ull, /* B9 */
+ 0x8000808080008000ull, /* BA */
+ 0x8000808080008080ull, /* BB */
+ 0x8000808080800000ull, /* BC */
+ 0x8000808080800080ull, /* BD */
+ 0x8000808080808000ull, /* BE */
+ 0x8000808080808080ull, /* BF */
+ 0x8080000000000000ull, /* C0 */
+ 0x8080000000000080ull, /* C1 */
+ 0x8080000000008000ull, /* C2 */
+ 0x8080000000008080ull, /* C3 */
+ 0x8080000000800000ull, /* C4 */
+ 0x8080000000800080ull, /* C5 */
+ 0x8080000000808000ull, /* C6 */
+ 0x8080000000808080ull, /* C7 */
+ 0x8080000080000000ull, /* C8 */
+ 0x8080000080000080ull, /* C9 */
+ 0x8080000080008000ull, /* CA */
+ 0x8080000080008080ull, /* CB */
+ 0x8080000080800000ull, /* CC */
+ 0x8080000080800080ull, /* CD */
+ 0x8080000080808000ull, /* CE */
+ 0x8080000080808080ull, /* CF */
+ 0x8080008000000000ull, /* D0 */
+ 0x8080008000000080ull, /* D1 */
+ 0x8080008000008000ull, /* D2 */
+ 0x8080008000008080ull, /* D3 */
+ 0x8080008000800000ull, /* D4 */
+ 0x8080008000800080ull, /* D5 */
+ 0x8080008000808000ull, /* D6 */
+ 0x8080008000808080ull, /* D7 */
+ 0x8080008080000000ull, /* D8 */
+ 0x8080008080000080ull, /* D9 */
+ 0x8080008080008000ull, /* DA */
+ 0x8080008080008080ull, /* DB */
+ 0x8080008080800000ull, /* DC */
+ 0x8080008080800080ull, /* DD */
+ 0x8080008080808000ull, /* DE */
+ 0x8080008080808080ull, /* DF */
+ 0x8080800000000000ull, /* E0 */
+ 0x8080800000000080ull, /* E1 */
+ 0x8080800000008000ull, /* E2 */
+ 0x8080800000008080ull, /* E3 */
+ 0x8080800000800000ull, /* E4 */
+ 0x8080800000800080ull, /* E5 */
+ 0x8080800000808000ull, /* E6 */
+ 0x8080800000808080ull, /* E7 */
+ 0x8080800080000000ull, /* E8 */
+ 0x8080800080000080ull, /* E9 */
+ 0x8080800080008000ull, /* EA */
+ 0x8080800080008080ull, /* EB */
+ 0x8080800080800000ull, /* EC */
+ 0x8080800080800080ull, /* ED */
+ 0x8080800080808000ull, /* EE */
+ 0x8080800080808080ull, /* EF */
+ 0x8080808000000000ull, /* F0 */
+ 0x8080808000000080ull, /* F1 */
+ 0x8080808000008000ull, /* F2 */
+ 0x8080808000008080ull, /* F3 */
+ 0x8080808000800000ull, /* F4 */
+ 0x8080808000800080ull, /* F5 */
+ 0x8080808000808000ull, /* F6 */
+ 0x8080808000808080ull, /* F7 */
+ 0x8080808080000000ull, /* F8 */
+ 0x8080808080000080ull, /* F9 */
+ 0x8080808080008000ull, /* FA */
+ 0x8080808080008080ull, /* FB */
+ 0x8080808080800000ull, /* FC */
+ 0x8080808080800080ull, /* FD */
+ 0x8080808080808000ull, /* FE */
+ 0x8080808080808080ull, /* FF */
+};
+
+void helper_vgbbd(ppc_avr_t *r, ppc_avr_t *b)
+{
+ int i;
+ uint64_t t[2] = { 0, 0 };
+
+ VECTOR_FOR_INORDER_I(i, u8) {
+#if defined(HOST_WORDS_BIGENDIAN)
+ t[i>>3] |= VGBBD_MASKS[b->u8[i]] >> (i & 7);
+#else
+ t[i>>3] |= VGBBD_MASKS[b->u8[i]] >> (7-(i & 7));
+#endif
+ }
+
+ r->u64[0] = t[0];
+ r->u64[1] = t[1];
+}
+
+#define PMSUM(name, srcfld, trgfld, trgtyp) \
+void helper_##name(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
+{ \
+ int i, j; \
+ trgtyp prod[sizeof(ppc_avr_t)/sizeof(a->srcfld[0])]; \
+ \
+ VECTOR_FOR_INORDER_I(i, srcfld) { \
+ prod[i] = 0; \
+ for (j = 0; j < sizeof(a->srcfld[0]) * 8; j++) { \
+ if (a->srcfld[i] & (1ull<<j)) { \
+ prod[i] ^= ((trgtyp)b->srcfld[i] << j); \
+ } \
+ } \
+ } \
+ \
+ VECTOR_FOR_INORDER_I(i, trgfld) { \
+ r->trgfld[i] = prod[2*i] ^ prod[2*i+1]; \
+ } \
+}
+
+PMSUM(vpmsumb, u8, u16, uint16_t)
+PMSUM(vpmsumh, u16, u32, uint32_t)
+PMSUM(vpmsumw, u32, u64, uint64_t)
+
+void helper_vpmsumd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+
+#ifdef CONFIG_INT128
+ int i, j;
+ __uint128_t prod[2];
+
+ VECTOR_FOR_INORDER_I(i, u64) {
+ prod[i] = 0;
+ for (j = 0; j < 64; j++) {
+ if (a->u64[i] & (1ull<<j)) {
+ prod[i] ^= (((__uint128_t)b->u64[i]) << j);
+ }
+ }
+ }
+
+ r->u128 = prod[0] ^ prod[1];
+
+#else
+ int i, j;
+ ppc_avr_t prod[2];
+
+ VECTOR_FOR_INORDER_I(i, u64) {
+ prod[i].u64[LO_IDX] = prod[i].u64[HI_IDX] = 0;
+ for (j = 0; j < 64; j++) {
+ if (a->u64[i] & (1ull<<j)) {
+ ppc_avr_t bshift;
+ if (j == 0) {
+ bshift.u64[HI_IDX] = 0;
+ bshift.u64[LO_IDX] = b->u64[i];
+ } else {
+ bshift.u64[HI_IDX] = b->u64[i] >> (64-j);
+ bshift.u64[LO_IDX] = b->u64[i] << j;
+ }
+ prod[i].u64[LO_IDX] ^= bshift.u64[LO_IDX];
+ prod[i].u64[HI_IDX] ^= bshift.u64[HI_IDX];
+ }
+ }
+ }
+
+ r->u64[LO_IDX] = prod[0].u64[LO_IDX] ^ prod[1].u64[LO_IDX];
+ r->u64[HI_IDX] = prod[0].u64[HI_IDX] ^ prod[1].u64[HI_IDX];
+#endif
+}
+
+
+#if defined(HOST_WORDS_BIGENDIAN)
#define PKBIG 1
#else
#define PKBIG 0
@@ -948,10 +1472,14 @@ VPK(shss, s16, s8, cvtshsb, 1)
VPK(shus, s16, u8, cvtshub, 1)
VPK(swss, s32, s16, cvtswsh, 1)
VPK(swus, s32, u16, cvtswuh, 1)
+VPK(sdss, s64, s32, cvtsdsw, 1)
+VPK(sdus, s64, u32, cvtsduw, 1)
VPK(uhus, u16, u8, cvtuhub, 1)
VPK(uwus, u32, u16, cvtuwuh, 1)
+VPK(udus, u64, u32, cvtuduw, 1)
VPK(uhum, u16, u8, I, 0)
VPK(uwum, u32, u16, I, 0)
+VPK(udum, u64, u32, I, 0)
#undef I
#undef VPK
#undef PKBIG
@@ -983,23 +1511,21 @@ VRFI(p, float_round_up)
VRFI(z, float_round_to_zero)
#undef VRFI
-#define VROTATE(suffix, element) \
+#define VROTATE(suffix, element, mask) \
void helper_vrl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
{ \
int i; \
\
for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
- unsigned int mask = ((1 << \
- (3 + (sizeof(a->element[0]) >> 1))) \
- - 1); \
unsigned int shift = b->element[i] & mask; \
r->element[i] = (a->element[i] << shift) | \
(a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
} \
}
-VROTATE(b, u8)
-VROTATE(h, u16)
-VROTATE(w, u32)
+VROTATE(b, u8, 0x7)
+VROTATE(h, u16, 0xF)
+VROTATE(w, u32, 0x1F)
+VROTATE(d, u64, 0x3F)
#undef VROTATE
void helper_vrsqrtefp(CPUPPCState *env, ppc_avr_t *r, ppc_avr_t *b)
@@ -1080,23 +1606,21 @@ VSHIFT(r, RIGHT)
#undef LEFT
#undef RIGHT
-#define VSL(suffix, element) \
+#define VSL(suffix, element, mask) \
void helper_vsl##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
{ \
int i; \
\
for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
- unsigned int mask = ((1 << \
- (3 + (sizeof(a->element[0]) >> 1))) \
- - 1); \
unsigned int shift = b->element[i] & mask; \
\
r->element[i] = a->element[i] << shift; \
} \
}
-VSL(b, u8)
-VSL(h, u16)
-VSL(w, u32)
+VSL(b, u8, 0x7)
+VSL(h, u16, 0x0F)
+VSL(w, u32, 0x1F)
+VSL(d, u64, 0x3F)
#undef VSL
void helper_vsldoi(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
@@ -1180,26 +1704,24 @@ VSPLTI(h, s16, int16_t)
VSPLTI(w, s32, int32_t)
#undef VSPLTI
-#define VSR(suffix, element) \
+#define VSR(suffix, element, mask) \
void helper_vsr##suffix(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
{ \
int i; \
\
for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
- unsigned int mask = ((1 << \
- (3 + (sizeof(a->element[0]) >> 1))) \
- - 1); \
unsigned int shift = b->element[i] & mask; \
- \
r->element[i] = a->element[i] >> shift; \
} \
}
-VSR(ab, s8)
-VSR(ah, s16)
-VSR(aw, s32)
-VSR(b, u8)
-VSR(h, u16)
-VSR(w, u32)
+VSR(ab, s8, 0x7)
+VSR(ah, s16, 0xF)
+VSR(aw, s32, 0x1F)
+VSR(ad, s64, 0x3F)
+VSR(b, u8, 0x7)
+VSR(h, u16, 0xF)
+VSR(w, u32, 0x1F)
+VSR(d, u64, 0x3F)
#undef VSR
void helper_vsro(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
@@ -1379,12 +1901,819 @@ VUPKPX(hpx, UPKHI)
}
VUPK(hsb, s16, s8, UPKHI)
VUPK(hsh, s32, s16, UPKHI)
+VUPK(hsw, s64, s32, UPKHI)
VUPK(lsb, s16, s8, UPKLO)
VUPK(lsh, s32, s16, UPKLO)
+VUPK(lsw, s64, s32, UPKLO)
#undef VUPK
#undef UPKHI
#undef UPKLO
+#define VGENERIC_DO(name, element) \
+ void helper_v##name(ppc_avr_t *r, ppc_avr_t *b) \
+ { \
+ int i; \
+ \
+ VECTOR_FOR_INORDER_I(i, element) { \
+ r->element[i] = name(b->element[i]); \
+ } \
+ }
+
+#define clzb(v) ((v) ? clz32((uint32_t)(v) << 24) : 8)
+#define clzh(v) ((v) ? clz32((uint32_t)(v) << 16) : 16)
+#define clzw(v) clz32((v))
+#define clzd(v) clz64((v))
+
+VGENERIC_DO(clzb, u8)
+VGENERIC_DO(clzh, u16)
+VGENERIC_DO(clzw, u32)
+VGENERIC_DO(clzd, u64)
+
+#undef clzb
+#undef clzh
+#undef clzw
+#undef clzd
+
+#define popcntb(v) ctpop8(v)
+#define popcnth(v) ctpop16(v)
+#define popcntw(v) ctpop32(v)
+#define popcntd(v) ctpop64(v)
+
+VGENERIC_DO(popcntb, u8)
+VGENERIC_DO(popcnth, u16)
+VGENERIC_DO(popcntw, u32)
+VGENERIC_DO(popcntd, u64)
+
+#undef popcntb
+#undef popcnth
+#undef popcntw
+#undef popcntd
+
+#undef VGENERIC_DO
+
+#if defined(HOST_WORDS_BIGENDIAN)
+#define QW_ONE { .u64 = { 0, 1 } }
+#else
+#define QW_ONE { .u64 = { 1, 0 } }
+#endif
+
+#ifndef CONFIG_INT128
+
+static inline void avr_qw_not(ppc_avr_t *t, ppc_avr_t a)
+{
+ t->u64[0] = ~a.u64[0];
+ t->u64[1] = ~a.u64[1];
+}
+
+static int avr_qw_cmpu(ppc_avr_t a, ppc_avr_t b)
+{
+ if (a.u64[HI_IDX] < b.u64[HI_IDX]) {
+ return -1;
+ } else if (a.u64[HI_IDX] > b.u64[HI_IDX]) {
+ return 1;
+ } else if (a.u64[LO_IDX] < b.u64[LO_IDX]) {
+ return -1;
+ } else if (a.u64[LO_IDX] > b.u64[LO_IDX]) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static void avr_qw_add(ppc_avr_t *t, ppc_avr_t a, ppc_avr_t b)
+{
+ t->u64[LO_IDX] = a.u64[LO_IDX] + b.u64[LO_IDX];
+ t->u64[HI_IDX] = a.u64[HI_IDX] + b.u64[HI_IDX] +
+ (~a.u64[LO_IDX] < b.u64[LO_IDX]);
+}
+
+static int avr_qw_addc(ppc_avr_t *t, ppc_avr_t a, ppc_avr_t b)
+{
+ ppc_avr_t not_a;
+ t->u64[LO_IDX] = a.u64[LO_IDX] + b.u64[LO_IDX];
+ t->u64[HI_IDX] = a.u64[HI_IDX] + b.u64[HI_IDX] +
+ (~a.u64[LO_IDX] < b.u64[LO_IDX]);
+ avr_qw_not(&not_a, a);
+ return avr_qw_cmpu(not_a, b) < 0;
+}
+
+#endif
+
+void helper_vadduqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+#ifdef CONFIG_INT128
+ r->u128 = a->u128 + b->u128;
+#else
+ avr_qw_add(r, *a, *b);
+#endif
+}
+
+void helper_vaddeuqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+#ifdef CONFIG_INT128
+ r->u128 = a->u128 + b->u128 + (c->u128 & 1);
+#else
+
+ if (c->u64[LO_IDX] & 1) {
+ ppc_avr_t tmp;
+
+ tmp.u64[HI_IDX] = 0;
+ tmp.u64[LO_IDX] = c->u64[LO_IDX] & 1;
+ avr_qw_add(&tmp, *a, tmp);
+ avr_qw_add(r, tmp, *b);
+ } else {
+ avr_qw_add(r, *a, *b);
+ }
+#endif
+}
+
+void helper_vaddcuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+#ifdef CONFIG_INT128
+ r->u128 = (~a->u128 < b->u128);
+#else
+ ppc_avr_t not_a;
+
+ avr_qw_not(&not_a, *a);
+
+ r->u64[HI_IDX] = 0;
+ r->u64[LO_IDX] = (avr_qw_cmpu(not_a, *b) < 0);
+#endif
+}
+
+void helper_vaddecuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+#ifdef CONFIG_INT128
+ int carry_out = (~a->u128 < b->u128);
+ if (!carry_out && (c->u128 & 1)) {
+ carry_out = ((a->u128 + b->u128 + 1) == 0) &&
+ ((a->u128 != 0) || (b->u128 != 0));
+ }
+ r->u128 = carry_out;
+#else
+
+ int carry_in = c->u64[LO_IDX] & 1;
+ int carry_out = 0;
+ ppc_avr_t tmp;
+
+ carry_out = avr_qw_addc(&tmp, *a, *b);
+
+ if (!carry_out && carry_in) {
+ ppc_avr_t one = QW_ONE;
+ carry_out = avr_qw_addc(&tmp, tmp, one);
+ }
+ r->u64[HI_IDX] = 0;
+ r->u64[LO_IDX] = carry_out;
+#endif
+}
+
+void helper_vsubuqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+#ifdef CONFIG_INT128
+ r->u128 = a->u128 - b->u128;
+#else
+ ppc_avr_t tmp;
+ ppc_avr_t one = QW_ONE;
+
+ avr_qw_not(&tmp, *b);
+ avr_qw_add(&tmp, *a, tmp);
+ avr_qw_add(r, tmp, one);
+#endif
+}
+
+void helper_vsubeuqm(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+#ifdef CONFIG_INT128
+ r->u128 = a->u128 + ~b->u128 + (c->u128 & 1);
+#else
+ ppc_avr_t tmp, sum;
+
+ avr_qw_not(&tmp, *b);
+ avr_qw_add(&sum, *a, tmp);
+
+ tmp.u64[HI_IDX] = 0;
+ tmp.u64[LO_IDX] = c->u64[LO_IDX] & 1;
+ avr_qw_add(r, sum, tmp);
+#endif
+}
+
+void helper_vsubcuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+#ifdef CONFIG_INT128
+ r->u128 = (~a->u128 < ~b->u128) ||
+ (a->u128 + ~b->u128 == (__uint128_t)-1);
+#else
+ int carry = (avr_qw_cmpu(*a, *b) > 0);
+ if (!carry) {
+ ppc_avr_t tmp;
+ avr_qw_not(&tmp, *b);
+ avr_qw_add(&tmp, *a, tmp);
+ carry = ((tmp.s64[HI_IDX] == -1ull) && (tmp.s64[LO_IDX] == -1ull));
+ }
+ r->u64[HI_IDX] = 0;
+ r->u64[LO_IDX] = carry;
+#endif
+}
+
+void helper_vsubecuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+#ifdef CONFIG_INT128
+ r->u128 =
+ (~a->u128 < ~b->u128) ||
+ ((c->u128 & 1) && (a->u128 + ~b->u128 == (__uint128_t)-1));
+#else
+ int carry_in = c->u64[LO_IDX] & 1;
+ int carry_out = (avr_qw_cmpu(*a, *b) > 0);
+ if (!carry_out && carry_in) {
+ ppc_avr_t tmp;
+ avr_qw_not(&tmp, *b);
+ avr_qw_add(&tmp, *a, tmp);
+ carry_out = ((tmp.u64[HI_IDX] == -1ull) && (tmp.u64[LO_IDX] == -1ull));
+ }
+
+ r->u64[HI_IDX] = 0;
+ r->u64[LO_IDX] = carry_out;
+#endif
+}
+
+#define BCD_PLUS_PREF_1 0xC
+#define BCD_PLUS_PREF_2 0xF
+#define BCD_PLUS_ALT_1 0xA
+#define BCD_NEG_PREF 0xD
+#define BCD_NEG_ALT 0xB
+#define BCD_PLUS_ALT_2 0xE
+
+#if defined(HOST_WORDS_BIGENDIAN)
+#define BCD_DIG_BYTE(n) (15 - (n/2))
+#else
+#define BCD_DIG_BYTE(n) (n/2)
+#endif
+
+static int bcd_get_sgn(ppc_avr_t *bcd)
+{
+ switch (bcd->u8[BCD_DIG_BYTE(0)] & 0xF) {
+ case BCD_PLUS_PREF_1:
+ case BCD_PLUS_PREF_2:
+ case BCD_PLUS_ALT_1:
+ case BCD_PLUS_ALT_2:
+ {
+ return 1;
+ }
+
+ case BCD_NEG_PREF:
+ case BCD_NEG_ALT:
+ {
+ return -1;
+ }
+
+ default:
+ {
+ return 0;
+ }
+ }
+}
+
+static int bcd_preferred_sgn(int sgn, int ps)
+{
+ if (sgn >= 0) {
+ return (ps == 0) ? BCD_PLUS_PREF_1 : BCD_PLUS_PREF_2;
+ } else {
+ return BCD_NEG_PREF;
+ }
+}
+
+static uint8_t bcd_get_digit(ppc_avr_t *bcd, int n, int *invalid)
+{
+ uint8_t result;
+ if (n & 1) {
+ result = bcd->u8[BCD_DIG_BYTE(n)] >> 4;
+ } else {
+ result = bcd->u8[BCD_DIG_BYTE(n)] & 0xF;
+ }
+
+ if (unlikely(result > 9)) {
+ *invalid = true;
+ }
+ return result;
+}
+
+static void bcd_put_digit(ppc_avr_t *bcd, uint8_t digit, int n)
+{
+ if (n & 1) {
+ bcd->u8[BCD_DIG_BYTE(n)] &= 0x0F;
+ bcd->u8[BCD_DIG_BYTE(n)] |= (digit<<4);
+ } else {
+ bcd->u8[BCD_DIG_BYTE(n)] &= 0xF0;
+ bcd->u8[BCD_DIG_BYTE(n)] |= digit;
+ }
+}
+
+static int bcd_cmp_mag(ppc_avr_t *a, ppc_avr_t *b)
+{
+ int i;
+ int invalid = 0;
+ for (i = 31; i > 0; i--) {
+ uint8_t dig_a = bcd_get_digit(a, i, &invalid);
+ uint8_t dig_b = bcd_get_digit(b, i, &invalid);
+ if (unlikely(invalid)) {
+ return 0; /* doesnt matter */
+ } else if (dig_a > dig_b) {
+ return 1;
+ } else if (dig_a < dig_b) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+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;
+ } else {
+ carry = 0;
+ }
+
+ bcd_put_digit(t, digit, i);
+
+ if (unlikely(*invalid)) {
+ return -1;
+ }
+ }
+
+ *overflow = carry;
+ return is_zero;
+}
+
+static int bcd_sub_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 & 0x80) {
+ carry = -1;
+ digit += 10;
+ } else {
+ carry = 0;
+ }
+
+ bcd_put_digit(t, digit, i);
+
+ if (unlikely(*invalid)) {
+ return -1;
+ }
+ }
+
+ *overflow = carry;
+ return is_zero;
+}
+
+uint32_t helper_bcdadd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
+{
+
+ int sgna = bcd_get_sgn(a);
+ 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.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps);
+ zero = bcd_add_mag(&result, a, b, &invalid, &overflow);
+ cr = (sgna > 0) ? 4 : 8;
+ } else if (bcd_cmp_mag(a, b) > 0) {
+ result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps);
+ zero = bcd_sub_mag(&result, a, b, &invalid, &overflow);
+ cr = (sgna > 0) ? 4 : 8;
+ } else {
+ result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgnb, ps);
+ zero = bcd_sub_mag(&result, b, a, &invalid, &overflow);
+ cr = (sgnb > 0) ? 4 : 8;
+ }
+ }
+
+ if (unlikely(invalid)) {
+ result.u64[HI_IDX] = result.u64[LO_IDX] = -1;
+ cr = 1;
+ } else if (overflow) {
+ cr |= 1;
+ } else if (zero) {
+ cr = 2;
+ }
+
+ *r = result;
+
+ return cr;
+}
+
+uint32_t helper_bcdsub(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
+{
+ ppc_avr_t bcopy = *b;
+ int sgnb = bcd_get_sgn(b);
+ if (sgnb < 0) {
+ bcd_put_digit(&bcopy, BCD_PLUS_PREF_1, 0);
+ } else if (sgnb > 0) {
+ bcd_put_digit(&bcopy, BCD_NEG_PREF, 0);
+ }
+ /* else invalid ... defer to bcdadd code for proper handling */
+
+ return helper_bcdadd(r, a, &bcopy, ps);
+}
+
+static uint8_t SBOX[256] = {
+0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5,
+0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
+0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0,
+0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
+0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC,
+0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
+0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A,
+0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
+0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0,
+0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
+0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B,
+0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
+0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85,
+0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
+0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
+0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
+0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17,
+0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
+0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88,
+0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
+0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C,
+0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
+0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9,
+0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
+0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6,
+0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
+0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E,
+0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
+0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94,
+0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
+0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68,
+0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16,
+};
+
+static void SubBytes(ppc_avr_t *r, ppc_avr_t *a)
+{
+ int i;
+ VECTOR_FOR_INORDER_I(i, u8) {
+ r->u8[i] = SBOX[a->u8[i]];
+ }
+}
+
+static uint8_t InvSBOX[256] = {
+0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38,
+0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
+0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87,
+0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
+0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D,
+0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
+0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2,
+0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
+0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16,
+0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
+0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA,
+0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
+0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A,
+0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
+0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02,
+0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
+0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA,
+0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
+0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85,
+0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
+0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89,
+0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
+0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20,
+0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
+0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31,
+0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
+0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D,
+0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
+0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0,
+0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
+0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26,
+0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D,
+};
+
+static void InvSubBytes(ppc_avr_t *r, ppc_avr_t *a)
+{
+ int i;
+ VECTOR_FOR_INORDER_I(i, u8) {
+ r->u8[i] = InvSBOX[a->u8[i]];
+ }
+}
+
+static uint8_t ROTL8(uint8_t x, int n)
+{
+ return (x << n) | (x >> (8-n));
+}
+
+static inline int BIT8(uint8_t x, int n)
+{
+ return (x & (0x80 >> n)) != 0;
+}
+
+static uint8_t GFx02(uint8_t x)
+{
+ return ROTL8(x, 1) ^ (BIT8(x, 0) ? 0x1A : 0);
+}
+
+static uint8_t GFx03(uint8_t x)
+{
+ return x ^ ROTL8(x, 1) ^ (BIT8(x, 0) ? 0x1A : 0);
+}
+
+static uint8_t GFx09(uint8_t x)
+{
+ uint8_t term2 = ROTL8(x, 3);
+ uint8_t term3 = (BIT8(x, 0) ? 0x68 : 0) | (BIT8(x, 1) ? 0x14 : 0) |
+ (BIT8(x, 2) ? 0x02 : 0);
+ uint8_t term4 = (BIT8(x, 1) ? 0x20 : 0) | (BIT8(x, 2) ? 0x18 : 0);
+ return x ^ term2 ^ term3 ^ term4;
+}
+
+static uint8_t GFx0B(uint8_t x)
+{
+ uint8_t term2 = ROTL8(x, 1);
+ uint8_t term3 = (x << 3) | (BIT8(x, 0) ? 0x06 : 0) |
+ (BIT8(x, 2) ? 0x01 : 0);
+ uint8_t term4 = (BIT8(x, 0) ? 0x70 : 0) | (BIT8(x, 1) ? 0x06 : 0) |
+ (BIT8(x, 2) ? 0x08 : 0);
+ uint8_t term5 = (BIT8(x, 1) ? 0x30 : 0) | (BIT8(x, 2) ? 0x02 : 0);
+ uint8_t term6 = BIT8(x, 2) ? 0x10 : 0;
+ return x ^ term2 ^ term3 ^ term4 ^ term5 ^ term6;
+}
+
+static uint8_t GFx0D(uint8_t x)
+{
+ uint8_t term2 = ROTL8(x, 2);
+ uint8_t term3 = (x << 3) | (BIT8(x, 1) ? 0x04 : 0) |
+ (BIT8(x, 2) ? 0x03 : 0);
+ uint8_t term4 = (BIT8(x, 0) ? 0x58 : 0) | (BIT8(x, 1) ? 0x20 : 0);
+ uint8_t term5 = (BIT8(x, 1) ? 0x08 : 0) | (BIT8(x, 2) ? 0x10 : 0);
+ uint8_t term6 = BIT8(x, 2) ? 0x08 : 0;
+ return x ^ term2 ^ term3 ^ term4 ^ term5 ^ term6;
+}
+
+static uint8_t GFx0E(uint8_t x)
+{
+ uint8_t term1 = ROTL8(x, 1);
+ uint8_t term2 = (x << 2) | (BIT8(x, 2) ? 0x02 : 0) |
+ (BIT8(x, 1) ? 0x01 : 0);
+ uint8_t term3 = (x << 3) | (BIT8(x, 1) ? 0x04 : 0) |
+ (BIT8(x, 2) ? 0x01 : 0);
+ uint8_t term4 = (BIT8(x, 0) ? 0x40 : 0) | (BIT8(x, 1) ? 0x28 : 0) |
+ (BIT8(x, 2) ? 0x10 : 0);
+ uint8_t term5 = (BIT8(x, 2) ? 0x08 : 0);
+ return term1 ^ term2 ^ term3 ^ term4 ^ term5;
+}
+
+#if defined(HOST_WORDS_BIGENDIAN)
+#define MCB(x, i, b) ((x)->u8[(i)*4 + (b)])
+#else
+#define MCB(x, i, b) ((x)->u8[15 - ((i)*4 + (b))])
+#endif
+
+static void MixColumns(ppc_avr_t *r, ppc_avr_t *x)
+{
+ int i;
+ for (i = 0; i < 4; i++) {
+ MCB(r, i, 0) = GFx02(MCB(x, i, 0)) ^ GFx03(MCB(x, i, 1)) ^
+ MCB(x, i, 2) ^ MCB(x, i, 3);
+ MCB(r, i, 1) = MCB(x, i, 0) ^ GFx02(MCB(x, i, 1)) ^
+ GFx03(MCB(x, i, 2)) ^ MCB(x, i, 3);
+ MCB(r, i, 2) = MCB(x, i, 0) ^ MCB(x, i, 1) ^
+ GFx02(MCB(x, i, 2)) ^ GFx03(MCB(x, i, 3));
+ MCB(r, i, 3) = GFx03(MCB(x, i, 0)) ^ MCB(x, i, 1) ^
+ MCB(x, i, 2) ^ GFx02(MCB(x, i, 3));
+ }
+}
+
+static void InvMixColumns(ppc_avr_t *r, ppc_avr_t *x)
+{
+ int i;
+ for (i = 0; i < 4; i++) {
+ MCB(r, i, 0) = GFx0E(MCB(x, i, 0)) ^ GFx0B(MCB(x, i, 1)) ^
+ GFx0D(MCB(x, i, 2)) ^ GFx09(MCB(x, i, 3));
+ MCB(r, i, 1) = GFx09(MCB(x, i, 0)) ^ GFx0E(MCB(x, i, 1)) ^
+ GFx0B(MCB(x, i, 2)) ^ GFx0D(MCB(x, i, 3));
+ MCB(r, i, 2) = GFx0D(MCB(x, i, 0)) ^ GFx09(MCB(x, i, 1)) ^
+ GFx0E(MCB(x, i, 2)) ^ GFx0B(MCB(x, i, 3));
+ MCB(r, i, 3) = GFx0B(MCB(x, i, 0)) ^ GFx0D(MCB(x, i, 1)) ^
+ GFx09(MCB(x, i, 2)) ^ GFx0E(MCB(x, i, 3));
+ }
+}
+
+static void ShiftRows(ppc_avr_t *r, ppc_avr_t *x)
+{
+ MCB(r, 0, 0) = MCB(x, 0, 0);
+ MCB(r, 1, 0) = MCB(x, 1, 0);
+ MCB(r, 2, 0) = MCB(x, 2, 0);
+ MCB(r, 3, 0) = MCB(x, 3, 0);
+
+ MCB(r, 0, 1) = MCB(x, 1, 1);
+ MCB(r, 1, 1) = MCB(x, 2, 1);
+ MCB(r, 2, 1) = MCB(x, 3, 1);
+ MCB(r, 3, 1) = MCB(x, 0, 1);
+
+ MCB(r, 0, 2) = MCB(x, 2, 2);
+ MCB(r, 1, 2) = MCB(x, 3, 2);
+ MCB(r, 2, 2) = MCB(x, 0, 2);
+ MCB(r, 3, 2) = MCB(x, 1, 2);
+
+ MCB(r, 0, 3) = MCB(x, 3, 3);
+ MCB(r, 1, 3) = MCB(x, 0, 3);
+ MCB(r, 2, 3) = MCB(x, 1, 3);
+ MCB(r, 3, 3) = MCB(x, 2, 3);
+}
+
+static void InvShiftRows(ppc_avr_t *r, ppc_avr_t *x)
+{
+ MCB(r, 0, 0) = MCB(x, 0, 0);
+ MCB(r, 1, 0) = MCB(x, 1, 0);
+ MCB(r, 2, 0) = MCB(x, 2, 0);
+ MCB(r, 3, 0) = MCB(x, 3, 0);
+
+ MCB(r, 0, 1) = MCB(x, 3, 1);
+ MCB(r, 1, 1) = MCB(x, 0, 1);
+ MCB(r, 2, 1) = MCB(x, 1, 1);
+ MCB(r, 3, 1) = MCB(x, 2, 1);
+
+ MCB(r, 0, 2) = MCB(x, 2, 2);
+ MCB(r, 1, 2) = MCB(x, 3, 2);
+ MCB(r, 2, 2) = MCB(x, 0, 2);
+ MCB(r, 3, 2) = MCB(x, 1, 2);
+
+ MCB(r, 0, 3) = MCB(x, 1, 3);
+ MCB(r, 1, 3) = MCB(x, 2, 3);
+ MCB(r, 2, 3) = MCB(x, 3, 3);
+ MCB(r, 3, 3) = MCB(x, 0, 3);
+}
+
+#undef MCB
+
+void helper_vsbox(ppc_avr_t *r, ppc_avr_t *a)
+{
+ SubBytes(r, a);
+}
+
+void helper_vcipher(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+ ppc_avr_t vtemp1, vtemp2, vtemp3;
+ SubBytes(&vtemp1, a);
+ ShiftRows(&vtemp2, &vtemp1);
+ MixColumns(&vtemp3, &vtemp2);
+ r->u64[0] = vtemp3.u64[0] ^ b->u64[0];
+ r->u64[1] = vtemp3.u64[1] ^ b->u64[1];
+}
+
+void helper_vcipherlast(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+ ppc_avr_t vtemp1, vtemp2;
+ SubBytes(&vtemp1, a);
+ ShiftRows(&vtemp2, &vtemp1);
+ r->u64[0] = vtemp2.u64[0] ^ b->u64[0];
+ r->u64[1] = vtemp2.u64[1] ^ b->u64[1];
+}
+
+void helper_vncipher(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+ /* This differs from what is written in ISA V2.07. The RTL is */
+ /* incorrect and will be fixed in V2.07B. */
+ ppc_avr_t vtemp1, vtemp2, vtemp3;
+ InvShiftRows(&vtemp1, a);
+ InvSubBytes(&vtemp2, &vtemp1);
+ vtemp3.u64[0] = vtemp2.u64[0] ^ b->u64[0];
+ vtemp3.u64[1] = vtemp2.u64[1] ^ b->u64[1];
+ InvMixColumns(r, &vtemp3);
+}
+
+void helper_vncipherlast(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
+{
+ ppc_avr_t vtemp1, vtemp2;
+ InvShiftRows(&vtemp1, a);
+ InvSubBytes(&vtemp2, &vtemp1);
+ r->u64[0] = vtemp2.u64[0] ^ b->u64[0];
+ r->u64[1] = vtemp2.u64[1] ^ b->u64[1];
+}
+
+#define ROTRu32(v, n) (((v) >> (n)) | ((v) << (32-n)))
+#if defined(HOST_WORDS_BIGENDIAN)
+#define EL_IDX(i) (i)
+#else
+#define EL_IDX(i) (3 - (i))
+#endif
+
+void helper_vshasigmaw(ppc_avr_t *r, ppc_avr_t *a, uint32_t st_six)
+{
+ int st = (st_six & 0x10) != 0;
+ int six = st_six & 0xF;
+ int i;
+
+ VECTOR_FOR_INORDER_I(i, u32) {
+ if (st == 0) {
+ if ((six & (0x8 >> i)) == 0) {
+ r->u32[EL_IDX(i)] = ROTRu32(a->u32[EL_IDX(i)], 7) ^
+ ROTRu32(a->u32[EL_IDX(i)], 18) ^
+ (a->u32[EL_IDX(i)] >> 3);
+ } else { /* six.bit[i] == 1 */
+ r->u32[EL_IDX(i)] = ROTRu32(a->u32[EL_IDX(i)], 17) ^
+ ROTRu32(a->u32[EL_IDX(i)], 19) ^
+ (a->u32[EL_IDX(i)] >> 10);
+ }
+ } else { /* st == 1 */
+ if ((six & (0x8 >> i)) == 0) {
+ r->u32[EL_IDX(i)] = ROTRu32(a->u32[EL_IDX(i)], 2) ^
+ ROTRu32(a->u32[EL_IDX(i)], 13) ^
+ ROTRu32(a->u32[EL_IDX(i)], 22);
+ } else { /* six.bit[i] == 1 */
+ r->u32[EL_IDX(i)] = ROTRu32(a->u32[EL_IDX(i)], 6) ^
+ ROTRu32(a->u32[EL_IDX(i)], 11) ^
+ ROTRu32(a->u32[EL_IDX(i)], 25);
+ }
+ }
+ }
+}
+
+#undef ROTRu32
+#undef EL_IDX
+
+#define ROTRu64(v, n) (((v) >> (n)) | ((v) << (64-n)))
+#if defined(HOST_WORDS_BIGENDIAN)
+#define EL_IDX(i) (i)
+#else
+#define EL_IDX(i) (1 - (i))
+#endif
+
+void helper_vshasigmad(ppc_avr_t *r, ppc_avr_t *a, uint32_t st_six)
+{
+ int st = (st_six & 0x10) != 0;
+ int six = st_six & 0xF;
+ int i;
+
+ VECTOR_FOR_INORDER_I(i, u64) {
+ if (st == 0) {
+ if ((six & (0x8 >> (2*i))) == 0) {
+ r->u64[EL_IDX(i)] = ROTRu64(a->u64[EL_IDX(i)], 1) ^
+ ROTRu64(a->u64[EL_IDX(i)], 8) ^
+ (a->u64[EL_IDX(i)] >> 7);
+ } else { /* six.bit[2*i] == 1 */
+ r->u64[EL_IDX(i)] = ROTRu64(a->u64[EL_IDX(i)], 19) ^
+ ROTRu64(a->u64[EL_IDX(i)], 61) ^
+ (a->u64[EL_IDX(i)] >> 6);
+ }
+ } else { /* st == 1 */
+ if ((six & (0x8 >> (2*i))) == 0) {
+ r->u64[EL_IDX(i)] = ROTRu64(a->u64[EL_IDX(i)], 28) ^
+ ROTRu64(a->u64[EL_IDX(i)], 34) ^
+ ROTRu64(a->u64[EL_IDX(i)], 39);
+ } else { /* six.bit[2*i] == 1 */
+ r->u64[EL_IDX(i)] = ROTRu64(a->u64[EL_IDX(i)], 14) ^
+ ROTRu64(a->u64[EL_IDX(i)], 18) ^
+ ROTRu64(a->u64[EL_IDX(i)], 41);
+ }
+ }
+ }
+}
+
+#undef ROTRu64
+#undef EL_IDX
+
+void helper_vpermxor(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
+{
+ int i;
+ VECTOR_FOR_INORDER_I(i, u8) {
+ int indexA = c->u8[i] >> 4;
+ int indexB = c->u8[i] & 0xF;
+#if defined(HOST_WORDS_BIGENDIAN)
+ r->u8[i] = a->u8[indexA] ^ b->u8[indexB];
+#else
+ r->u8[i] = a->u8[15-indexA] ^ b->u8[15-indexB];
+#endif
+ }
+}
+
#undef VECTOR_FOR_INORDER_I
#undef HI_IDX
#undef LO_IDX
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 7af3fe277d..32e7a8c0a7 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -36,6 +36,7 @@
#include "hw/ppc/spapr.h"
#include "hw/ppc/spapr_vio.h"
#include "sysemu/watchdog.h"
+#include "trace.h"
//#define DEBUG_KVM
@@ -401,7 +402,7 @@ static inline void kvm_fixup_page_sizes(PowerPCCPU *cpu)
unsigned long kvm_arch_vcpu_id(CPUState *cpu)
{
- return cpu->cpu_index;
+ return ppc_get_vcpu_dt_id(POWERPC_CPU(cpu));
}
int kvm_arch_init_vcpu(CPUState *cs)
@@ -480,8 +481,7 @@ static void kvm_get_one_spr(CPUState *cs, uint64_t id, int spr)
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
if (ret != 0) {
- fprintf(stderr, "Warning: Unable to retrieve SPR %d from KVM: %s\n",
- spr, strerror(errno));
+ trace_kvm_failed_spr_get(spr, strerror(errno));
} else {
switch (id & KVM_REG_SIZE_MASK) {
case KVM_REG_SIZE_U32:
@@ -529,8 +529,7 @@ static void kvm_put_one_spr(CPUState *cs, uint64_t id, int spr)
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
if (ret != 0) {
- fprintf(stderr, "Warning: Unable to set SPR %d to KVM: %s\n",
- spr, strerror(errno));
+ trace_kvm_failed_spr_set(spr, strerror(errno));
}
}
@@ -820,6 +819,9 @@ int kvm_arch_put_registers(CPUState *cs, int level)
#ifdef TARGET_PPC64
for (i = 0; i < ARRAY_SIZE(env->slb); i++) {
sregs.u.s.ppc64.slb[i].slbe = env->slb[i].esid;
+ if (env->slb[i].esid & SLB_ESID_V) {
+ sregs.u.s.ppc64.slb[i].slbe |= i;
+ }
sregs.u.s.ppc64.slb[i].slbv = env->slb[i].vsid;
}
#endif
@@ -1029,7 +1031,9 @@ int kvm_arch_get_registers(CPUState *cs)
return ret;
}
- ppc_store_sdr1(env, sregs.u.s.sdr1);
+ if (!env->external_htab) {
+ ppc_store_sdr1(env, sregs.u.s.sdr1);
+ }
/* Sync SLB */
#ifdef TARGET_PPC64
@@ -1766,22 +1770,14 @@ static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data)
}
}
-int kvmppc_fixup_cpu(PowerPCCPU *cpu)
+bool kvmppc_has_cap_epr(void)
{
- CPUState *cs = CPU(cpu);
- int smt;
-
- /* Adjust cpu index for SMT */
- smt = kvmppc_smt_threads();
- cs->cpu_index = (cs->cpu_index / smp_threads) * smt
- + (cs->cpu_index % smp_threads);
-
- return 0;
+ return cap_epr;
}
-bool kvmppc_has_cap_epr(void)
+bool kvmppc_has_cap_htab_fd(void)
{
- return cap_epr;
+ return cap_htab_fd;
}
static int kvm_ppc_register_host_cpu_type(void)
@@ -1934,3 +1930,88 @@ void kvm_arch_remove_all_hw_breakpoints(void)
void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
{
}
+
+struct kvm_get_htab_buf {
+ struct kvm_get_htab_header header;
+ /*
+ * We require one extra byte for read
+ */
+ target_ulong hpte[(HPTES_PER_GROUP * 2) + 1];
+};
+
+uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu, target_ulong pte_index)
+{
+ int htab_fd;
+ struct kvm_get_htab_fd ghf;
+ struct kvm_get_htab_buf *hpte_buf;
+
+ ghf.flags = 0;
+ ghf.start_index = pte_index;
+ htab_fd = kvm_vm_ioctl(kvm_state, KVM_PPC_GET_HTAB_FD, &ghf);
+ if (htab_fd < 0) {
+ goto error_out;
+ }
+
+ hpte_buf = g_malloc0(sizeof(*hpte_buf));
+ /*
+ * Read the hpte group
+ */
+ if (read(htab_fd, hpte_buf, sizeof(*hpte_buf)) < 0) {
+ goto out_close;
+ }
+
+ close(htab_fd);
+ return (uint64_t)(uintptr_t) hpte_buf->hpte;
+
+out_close:
+ g_free(hpte_buf);
+ close(htab_fd);
+error_out:
+ return 0;
+}
+
+void kvmppc_hash64_free_pteg(uint64_t token)
+{
+ struct kvm_get_htab_buf *htab_buf;
+
+ htab_buf = container_of((void *)(uintptr_t) token, struct kvm_get_htab_buf,
+ hpte);
+ g_free(htab_buf);
+ return;
+}
+
+void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index,
+ target_ulong pte0, target_ulong pte1)
+{
+ int htab_fd;
+ struct kvm_get_htab_fd ghf;
+ struct kvm_get_htab_buf hpte_buf;
+
+ ghf.flags = 0;
+ ghf.start_index = 0; /* Ignored */
+ htab_fd = kvm_vm_ioctl(kvm_state, KVM_PPC_GET_HTAB_FD, &ghf);
+ if (htab_fd < 0) {
+ goto error_out;
+ }
+
+ hpte_buf.header.n_valid = 1;
+ hpte_buf.header.n_invalid = 0;
+ hpte_buf.header.index = pte_index;
+ hpte_buf.hpte[0] = pte0;
+ hpte_buf.hpte[1] = pte1;
+ /*
+ * Write the hpte entry.
+ * CAUTION: write() has the warn_unused_result attribute. Hence we
+ * need to check the return value, even though we do nothing.
+ */
+ if (write(htab_fd, &hpte_buf, sizeof(hpte_buf)) < 0) {
+ goto out_close;
+ }
+
+out_close:
+ close(htab_fd);
+ return;
+
+error_out:
+ return;
+}
diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h
index 5f78e4be14..ff077ec502 100644
--- a/target-ppc/kvm_ppc.h
+++ b/target-ppc/kvm_ppc.h
@@ -36,13 +36,18 @@ int kvmppc_remove_spapr_tce(void *table, int pfd, uint32_t window_size);
int kvmppc_reset_htab(int shift_hint);
uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift);
#endif /* !CONFIG_USER_ONLY */
-int kvmppc_fixup_cpu(PowerPCCPU *cpu);
bool kvmppc_has_cap_epr(void);
int kvmppc_define_rtas_kernel_token(uint32_t token, const char *function);
+bool kvmppc_has_cap_htab_fd(void);
int kvmppc_get_htab_fd(bool write);
int kvmppc_save_htab(QEMUFile *f, int fd, size_t bufsize, int64_t max_ns);
int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index,
uint16_t n_valid, uint16_t n_invalid);
+uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu, target_ulong pte_index);
+void kvmppc_hash64_free_pteg(uint64_t token);
+
+void kvmppc_hash64_write_pte(CPUPPCState *env, target_ulong pte_index,
+ target_ulong pte0, target_ulong pte1);
#else
@@ -155,11 +160,6 @@ static inline int kvmppc_update_sdr1(CPUPPCState *env)
#endif /* !CONFIG_USER_ONLY */
-static inline int kvmppc_fixup_cpu(PowerPCCPU *cpu)
-{
- return -1;
-}
-
static inline bool kvmppc_has_cap_epr(void)
{
return false;
@@ -171,6 +171,11 @@ static inline int kvmppc_define_rtas_kernel_token(uint32_t token,
return -1;
}
+static inline bool kvmppc_has_cap_htab_fd(void)
+{
+ return false;
+}
+
static inline int kvmppc_get_htab_fd(bool write)
{
return -1;
@@ -188,6 +193,24 @@ static inline int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index,
abort();
}
+static inline uint64_t kvmppc_hash64_read_pteg(PowerPCCPU *cpu,
+ target_ulong pte_index)
+{
+ abort();
+}
+
+static inline void kvmppc_hash64_free_pteg(uint64_t token)
+{
+ abort();
+}
+
+static inline void kvmppc_hash64_write_pte(CPUPPCState *env,
+ target_ulong pte_index,
+ target_ulong pte0, target_ulong pte1)
+{
+ abort();
+}
+
#endif
#ifndef CONFIG_KVM
diff --git a/target-ppc/machine.c b/target-ppc/machine.c
index 12c174f7f3..2d46ceccca 100644
--- a/target-ppc/machine.c
+++ b/target-ppc/machine.c
@@ -70,7 +70,9 @@ static int cpu_load_old(QEMUFile *f, void *opaque, int version_id)
qemu_get_betls(f, &env->pb[i]);
for (i = 0; i < 1024; i++)
qemu_get_betls(f, &env->spr[i]);
- ppc_store_sdr1(env, sdr1);
+ if (!env->external_htab) {
+ ppc_store_sdr1(env, sdr1);
+ }
qemu_get_be32s(f, &env->vscr);
qemu_get_be64s(f, &env->spe_acc);
qemu_get_be32s(f, &env->spe_fscr);
@@ -179,9 +181,10 @@ static int cpu_post_load(void *opaque, int version_id)
env->IBAT[1][i+4] = env->spr[SPR_IBAT4U + 2*i + 1];
}
- /* Restore htab_base and htab_mask variables */
- ppc_store_sdr1(env, env->spr[SPR_SDR1]);
-
+ if (!env->external_htab) {
+ /* Restore htab_base and htab_mask variables */
+ ppc_store_sdr1(env, env->spr[SPR_SDR1]);
+ }
hreg_compute_hflags(env);
hreg_compute_mem_idx(env);
diff --git a/target-ppc/misc_helper.c b/target-ppc/misc_helper.c
index 616aab6fb6..dc2ebfc452 100644
--- a/target-ppc/misc_helper.c
+++ b/target-ppc/misc_helper.c
@@ -38,7 +38,9 @@ void helper_store_dump_spr(CPUPPCState *env, uint32_t sprn)
void helper_store_sdr1(CPUPPCState *env, target_ulong val)
{
- ppc_store_sdr1(env, val);
+ if (!env->external_htab) {
+ ppc_store_sdr1(env, val);
+ }
}
void helper_store_hid0_601(CPUPPCState *env, target_ulong val)
diff --git a/target-ppc/mmu-hash64.c b/target-ppc/mmu-hash64.c
index 67fc1b5dec..f2af4fbaa7 100644
--- a/target-ppc/mmu-hash64.c
+++ b/target-ppc/mmu-hash64.c
@@ -41,6 +41,11 @@
#endif
/*
+ * Used to indicate whether we have allocated htab in the
+ * host kernel
+ */
+bool kvmppc_kern_htab;
+/*
* SLB handling
*/
@@ -278,12 +283,12 @@ static int ppc_hash64_pte_prot(CPUPPCState *env,
static int ppc_hash64_amr_prot(CPUPPCState *env, ppc_hash_pte64_t pte)
{
int key, amrbits;
- int prot = PAGE_EXEC;
+ int prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
/* Only recent MMUs implement Virtual Page Class Key Protection */
if (!(env->mmu_model & POWERPC_MMU_AMR)) {
- return PAGE_READ | PAGE_WRITE | PAGE_EXEC;
+ return prot;
}
key = HPTE64_R_KEY(pte.pte1);
@@ -292,39 +297,94 @@ static int ppc_hash64_amr_prot(CPUPPCState *env, ppc_hash_pte64_t pte)
/* fprintf(stderr, "AMR protection: key=%d AMR=0x%" PRIx64 "\n", key, */
/* env->spr[SPR_AMR]); */
+ /*
+ * A store is permitted if the AMR bit is 0. Remove write
+ * protection if it is set.
+ */
if (amrbits & 0x2) {
- prot |= PAGE_WRITE;
+ prot &= ~PAGE_WRITE;
}
+ /*
+ * A load is permitted if the AMR bit is 0. Remove read
+ * protection if it is set.
+ */
if (amrbits & 0x1) {
- prot |= PAGE_READ;
+ prot &= ~PAGE_READ;
}
return prot;
}
-static hwaddr ppc_hash64_pteg_search(CPUPPCState *env, hwaddr pteg_off,
+uint64_t ppc_hash64_start_access(PowerPCCPU *cpu, target_ulong pte_index)
+{
+ uint64_t token = 0;
+ hwaddr pte_offset;
+
+ pte_offset = pte_index * HASH_PTE_SIZE_64;
+ if (kvmppc_kern_htab) {
+ /*
+ * HTAB is controlled by KVM. Fetch the PTEG into a new buffer.
+ */
+ token = kvmppc_hash64_read_pteg(cpu, pte_index);
+ if (token) {
+ return token;
+ }
+ /*
+ * pteg read failed, even though we have allocated htab via
+ * kvmppc_reset_htab.
+ */
+ return 0;
+ }
+ /*
+ * HTAB is controlled by QEMU. Just point to the internally
+ * accessible PTEG.
+ */
+ if (cpu->env.external_htab) {
+ token = (uint64_t)(uintptr_t) cpu->env.external_htab + pte_offset;
+ } else if (cpu->env.htab_base) {
+ token = cpu->env.htab_base + pte_offset;
+ }
+ return token;
+}
+
+void ppc_hash64_stop_access(uint64_t token)
+{
+ if (kvmppc_kern_htab) {
+ return kvmppc_hash64_free_pteg(token);
+ }
+}
+
+static hwaddr ppc_hash64_pteg_search(CPUPPCState *env, hwaddr hash,
bool secondary, target_ulong ptem,
ppc_hash_pte64_t *pte)
{
- hwaddr pte_offset = pteg_off;
- target_ulong pte0, pte1;
int i;
+ uint64_t token;
+ target_ulong pte0, pte1;
+ target_ulong pte_index;
+ pte_index = (hash & env->htab_mask) * HPTES_PER_GROUP;
+ token = ppc_hash64_start_access(ppc_env_get_cpu(env), pte_index);
+ if (!token) {
+ return -1;
+ }
for (i = 0; i < HPTES_PER_GROUP; i++) {
- pte0 = ppc_hash64_load_hpte0(env, pte_offset);
- pte1 = ppc_hash64_load_hpte1(env, pte_offset);
+ pte0 = ppc_hash64_load_hpte0(env, token, i);
+ pte1 = ppc_hash64_load_hpte1(env, token, i);
if ((pte0 & HPTE64_V_VALID)
&& (secondary == !!(pte0 & HPTE64_V_SECONDARY))
&& HPTE64_V_COMPARE(pte0, ptem)) {
pte->pte0 = pte0;
pte->pte1 = pte1;
- return pte_offset;
+ ppc_hash64_stop_access(token);
+ return (pte_index + i) * HASH_PTE_SIZE_64;
}
-
- pte_offset += HASH_PTE_SIZE_64;
}
-
+ ppc_hash64_stop_access(token);
+ /*
+ * We didn't find a valid entry.
+ */
return -1;
}
@@ -332,7 +392,7 @@ static hwaddr ppc_hash64_htab_lookup(CPUPPCState *env,
ppc_slb_t *slb, target_ulong eaddr,
ppc_hash_pte64_t *pte)
{
- hwaddr pteg_off, pte_offset;
+ hwaddr pte_offset;
hwaddr hash;
uint64_t vsid, epnshift, epnmask, epn, ptem;
@@ -367,8 +427,7 @@ static hwaddr ppc_hash64_htab_lookup(CPUPPCState *env,
" vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
" hash=" TARGET_FMT_plx "\n",
env->htab_base, env->htab_mask, vsid, ptem, hash);
- pteg_off = (hash * HASH_PTEG_SIZE_64) & env->htab_mask;
- pte_offset = ppc_hash64_pteg_search(env, pteg_off, 0, ptem, pte);
+ pte_offset = ppc_hash64_pteg_search(env, hash, 0, ptem, pte);
if (pte_offset == -1) {
/* Secondary PTEG lookup */
@@ -377,8 +436,7 @@ static hwaddr ppc_hash64_htab_lookup(CPUPPCState *env,
" hash=" TARGET_FMT_plx "\n", env->htab_base,
env->htab_mask, vsid, ptem, ~hash);
- pteg_off = (~hash * HASH_PTEG_SIZE_64) & env->htab_mask;
- pte_offset = ppc_hash64_pteg_search(env, pteg_off, 1, ptem, pte);
+ pte_offset = ppc_hash64_pteg_search(env, ~hash, 1, ptem, pte);
}
return pte_offset;
@@ -508,7 +566,8 @@ int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong eaddr,
}
if (new_pte1 != pte.pte1) {
- ppc_hash64_store_hpte1(env, pte_offset, new_pte1);
+ ppc_hash64_store_hpte(env, pte_offset / HASH_PTE_SIZE_64,
+ pte.pte0, new_pte1);
}
/* 7. Determine the real address from the PTE */
@@ -544,3 +603,23 @@ hwaddr ppc_hash64_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
return ppc_hash64_pte_raddr(slb, pte, addr) & TARGET_PAGE_MASK;
}
+
+void ppc_hash64_store_hpte(CPUPPCState *env,
+ target_ulong pte_index,
+ target_ulong pte0, target_ulong pte1)
+{
+ CPUState *cs = ENV_GET_CPU(env);
+
+ if (kvmppc_kern_htab) {
+ return kvmppc_hash64_write_pte(env, pte_index, pte0, pte1);
+ }
+
+ pte_index *= HASH_PTE_SIZE_64;
+ if (env->external_htab) {
+ stq_p(env->external_htab + pte_index, pte0);
+ stq_p(env->external_htab + pte_index + HASH_PTE_SIZE_64/2, pte1);
+ } else {
+ stq_phys(cs->as, env->htab_base + pte_index, pte0);
+ stq_phys(cs->as, env->htab_base + pte_index + HASH_PTE_SIZE_64/2, pte1);
+ }
+}
diff --git a/target-ppc/mmu-hash64.h b/target-ppc/mmu-hash64.h
index a8da558ca2..1746b3e2d3 100644
--- a/target-ppc/mmu-hash64.h
+++ b/target-ppc/mmu-hash64.h
@@ -9,6 +9,8 @@ int ppc_store_slb (CPUPPCState *env, target_ulong rb, target_ulong rs);
hwaddr ppc_hash64_get_phys_page_debug(CPUPPCState *env, target_ulong addr);
int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
int mmu_idx);
+void ppc_hash64_store_hpte(CPUPPCState *env, target_ulong index,
+ target_ulong pte0, target_ulong pte1);
#endif
/*
@@ -75,49 +77,34 @@ int ppc_hash64_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
#define HPTE64_V_1TB_SEG 0x4000000000000000ULL
#define HPTE64_V_VRMA_MASK 0x4001ffffff000000ULL
-static inline target_ulong ppc_hash64_load_hpte0(CPUPPCState *env,
- hwaddr pte_offset)
-{
- CPUState *cs = ENV_GET_CPU(env);
- if (env->external_htab) {
- return ldq_p(env->external_htab + pte_offset);
- } else {
- return ldq_phys(cs->as, env->htab_base + pte_offset);
- }
-}
-static inline target_ulong ppc_hash64_load_hpte1(CPUPPCState *env,
- hwaddr pte_offset)
-{
- CPUState *cs = ENV_GET_CPU(env);
- if (env->external_htab) {
- return ldq_p(env->external_htab + pte_offset + HASH_PTE_SIZE_64/2);
- } else {
- return ldq_phys(cs->as,
- env->htab_base + pte_offset + HASH_PTE_SIZE_64/2);
- }
-}
+extern bool kvmppc_kern_htab;
+uint64_t ppc_hash64_start_access(PowerPCCPU *cpu, target_ulong pte_index);
+void ppc_hash64_stop_access(uint64_t token);
-static inline void ppc_hash64_store_hpte0(CPUPPCState *env,
- hwaddr pte_offset, target_ulong pte0)
+static inline target_ulong ppc_hash64_load_hpte0(CPUPPCState *env,
+ uint64_t token, int index)
{
CPUState *cs = ENV_GET_CPU(env);
+ uint64_t addr;
+ addr = token + (index * HASH_PTE_SIZE_64);
if (env->external_htab) {
- stq_p(env->external_htab + pte_offset, pte0);
+ return ldq_p((const void *)(uintptr_t)addr);
} else {
- stq_phys(cs->as, env->htab_base + pte_offset, pte0);
+ return ldq_phys(cs->as, addr);
}
}
-static inline void ppc_hash64_store_hpte1(CPUPPCState *env,
- hwaddr pte_offset, target_ulong pte1)
+static inline target_ulong ppc_hash64_load_hpte1(CPUPPCState *env,
+ uint64_t token, int index)
{
CPUState *cs = ENV_GET_CPU(env);
+ uint64_t addr;
+ addr = token + (index * HASH_PTE_SIZE_64) + HASH_PTE_SIZE_64/2;
if (env->external_htab) {
- stq_p(env->external_htab + pte_offset + HASH_PTE_SIZE_64/2, pte1);
+ return ldq_p((const void *)(uintptr_t)addr);
} else {
- stq_phys(cs->as,
- env->htab_base + pte_offset + HASH_PTE_SIZE_64/2, pte1);
+ return ldq_phys(cs->as, addr);
}
}
diff --git a/target-ppc/mmu_helper.c b/target-ppc/mmu_helper.c
index 04a840b016..8e2f8e736a 100644
--- a/target-ppc/mmu_helper.c
+++ b/target-ppc/mmu_helper.c
@@ -2014,6 +2014,7 @@ void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
{
LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value);
+ assert(!env->external_htab);
if (env->spr[SPR_SDR1] != value) {
env->spr[SPR_SDR1] = value;
#if defined(TARGET_PPC64)
@@ -2025,7 +2026,7 @@ void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
" stored in SDR1\n", htabsize);
htabsize = 28;
}
- env->htab_mask = (1ULL << (htabsize + 18)) - 1;
+ env->htab_mask = (1ULL << (htabsize + 18 - 7)) - 1;
env->htab_base = value & SDR_64_HTABORG;
} else
#endif /* defined(TARGET_PPC64) */
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index c5c1108e92..91c33dcd1d 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -387,6 +387,8 @@ EXTRACT_HELPER(opc2, 1, 5);
EXTRACT_HELPER(opc3, 6, 5);
/* Update Cr0 flags */
EXTRACT_HELPER(Rc, 0, 1);
+/* Update Cr6 flags (Altivec) */
+EXTRACT_HELPER(Rc21, 10, 1);
/* Destination */
EXTRACT_HELPER(rD, 21, 5);
/* Source */
@@ -622,6 +624,20 @@ static opc_handler_t invalid_handler = {
.handler = gen_invalid,
};
+#if defined(TARGET_PPC64)
+/* NOTE: as this time, the only use of is_user_mode() is in 64 bit code. And */
+/* so the function is wrapped in the standard 64-bit ifdef in order to */
+/* avoid compiler warnings in 32-bit implementations. */
+static bool is_user_mode(DisasContext *ctx)
+{
+#if defined(CONFIG_USER_ONLY)
+ return true;
+#else
+ return ctx->mem_idx == 0;
+#endif
+}
+#endif
+
/*** Integer comparison ***/
static inline void gen_op_cmp(TCGv arg0, TCGv arg1, int s, int crf)
@@ -984,6 +1000,25 @@ GEN_INT_ARITH_DIVW(divwuo, 0x1E, 0, 1);
/* divw divw. divwo divwo. */
GEN_INT_ARITH_DIVW(divw, 0x0F, 1, 0);
GEN_INT_ARITH_DIVW(divwo, 0x1F, 1, 1);
+
+/* div[wd]eu[o][.] */
+#define GEN_DIVE(name, hlpr, compute_ov) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ TCGv_i32 t0 = tcg_const_i32(compute_ov); \
+ gen_helper_##hlpr(cpu_gpr[rD(ctx->opcode)], cpu_env, \
+ cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)], t0); \
+ tcg_temp_free_i32(t0); \
+ if (unlikely(Rc(ctx->opcode) != 0)) { \
+ gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]); \
+ } \
+}
+
+GEN_DIVE(divweu, divweu, 0);
+GEN_DIVE(divweuo, divweu, 1);
+GEN_DIVE(divwe, divwe, 0);
+GEN_DIVE(divweo, divwe, 1);
+
#if defined(TARGET_PPC64)
static inline void gen_op_arith_divd(DisasContext *ctx, TCGv ret, TCGv arg1,
TCGv arg2, int sign, int compute_ov)
@@ -1032,6 +1067,11 @@ GEN_INT_ARITH_DIVD(divduo, 0x1E, 0, 1);
/* divw divw. divwo divwo. */
GEN_INT_ARITH_DIVD(divd, 0x0F, 1, 0);
GEN_INT_ARITH_DIVD(divdo, 0x1F, 1, 1);
+
+GEN_DIVE(divdeu, divdeu, 0);
+GEN_DIVE(divdeuo, divdeu, 1);
+GEN_DIVE(divde, divde, 0);
+GEN_DIVE(divdeo, divde, 1);
#endif
/* mulhw mulhw. */
@@ -1525,6 +1565,15 @@ static void gen_prtyd(DisasContext *ctx)
#endif
#if defined(TARGET_PPC64)
+/* bpermd */
+static void gen_bpermd(DisasContext *ctx)
+{
+ gen_helper_bpermd(cpu_gpr[rA(ctx->opcode)],
+ cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
+}
+#endif
+
+#if defined(TARGET_PPC64)
/* extsw & extsw. */
GEN_LOGICAL1(extsw, tcg_gen_ext32s_tl, 0x1E, PPC_64B);
@@ -2169,17 +2218,31 @@ GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT);
/*** Floating-Point round & convert ***/
/* fctiw */
GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT);
+/* fctiwu */
+GEN_FLOAT_B(ctiwu, 0x0E, 0x04, 0, PPC2_FP_CVT_ISA206);
/* fctiwz */
GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT);
+/* fctiwuz */
+GEN_FLOAT_B(ctiwuz, 0x0F, 0x04, 0, PPC2_FP_CVT_ISA206);
/* frsp */
GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT);
#if defined(TARGET_PPC64)
/* fcfid */
GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC_64B);
+/* fcfids */
+GEN_FLOAT_B(cfids, 0x0E, 0x1A, 0, PPC2_FP_CVT_ISA206);
+/* fcfidu */
+GEN_FLOAT_B(cfidu, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206);
+/* fcfidus */
+GEN_FLOAT_B(cfidus, 0x0E, 0x1E, 0, PPC2_FP_CVT_ISA206);
/* fctid */
GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC_64B);
+/* fctidu */
+GEN_FLOAT_B(ctidu, 0x0E, 0x1D, 0, PPC2_FP_CVT_ISA206);
/* fctidz */
GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC_64B);
+/* fctidu */
+GEN_FLOAT_B(ctiduz, 0x0F, 0x1D, 0, PPC2_FP_CVT_ISA206);
#endif
/* frin */
@@ -2191,6 +2254,27 @@ GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT);
/* frim */
GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT);
+static void gen_ftdiv(DisasContext *ctx)
+{
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+ gen_helper_ftdiv(cpu_crf[crfD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],
+ cpu_fpr[rB(ctx->opcode)]);
+}
+
+static void gen_ftsqrt(DisasContext *ctx)
+{
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+ gen_helper_ftsqrt(cpu_crf[crfD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
+}
+
+
+
/*** Floating-Point compare ***/
/* fcmpo */
@@ -2294,6 +2378,32 @@ static void gen_fcpsgn(DisasContext *ctx)
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0);
}
+static void gen_fmrgew(DisasContext *ctx)
+{
+ TCGv_i64 b0;
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+ b0 = tcg_temp_new_i64();
+ tcg_gen_shri_i64(b0, cpu_fpr[rB(ctx->opcode)], 32);
+ tcg_gen_deposit_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],
+ b0, 0, 32);
+ tcg_temp_free_i64(b0);
+}
+
+static void gen_fmrgow(DisasContext *ctx)
+{
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+ tcg_gen_deposit_i64(cpu_fpr[rD(ctx->opcode)],
+ cpu_fpr[rB(ctx->opcode)],
+ cpu_fpr[rA(ctx->opcode)],
+ 32, 32);
+}
+
/*** Floating-Point status & ctrl register ***/
/* mcrfs */
@@ -2585,6 +2695,14 @@ static inline void gen_qemu_ld32s(DisasContext *ctx, TCGv arg1, TCGv arg2)
tcg_gen_qemu_ld32s(arg1, arg2, ctx->mem_idx);
}
+static void gen_qemu_ld32s_i64(DisasContext *ctx, TCGv_i64 val, TCGv addr)
+{
+ TCGv tmp = tcg_temp_new();
+ gen_qemu_ld32s(ctx, tmp, addr);
+ tcg_gen_ext_tl_i64(val, tmp);
+ tcg_temp_free(tmp);
+}
+
static inline void gen_qemu_ld64(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
{
tcg_gen_qemu_ld64(arg1, arg2, ctx->mem_idx);
@@ -2756,36 +2874,44 @@ static void gen_ld(DisasContext *ctx)
/* lq */
static void gen_lq(DisasContext *ctx)
{
-#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
-#else
int ra, rd;
TCGv EA;
- /* Restore CPU state */
- if (unlikely(ctx->mem_idx == 0)) {
+ /* lq is a legal user mode instruction starting in ISA 2.07 */
+ bool legal_in_user_mode = (ctx->insns_flags2 & PPC2_LSQ_ISA207) != 0;
+ bool le_is_supported = (ctx->insns_flags2 & PPC2_LSQ_ISA207) != 0;
+
+ if (!legal_in_user_mode && is_user_mode(ctx)) {
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return;
}
+
+ if (!le_is_supported && ctx->le_mode) {
+ gen_exception_err(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE);
+ return;
+ }
+
ra = rA(ctx->opcode);
rd = rD(ctx->opcode);
if (unlikely((rd & 1) || rd == ra)) {
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
return;
}
- if (unlikely(ctx->le_mode)) {
- /* Little-endian mode is not handled */
- gen_exception_err(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE);
- return;
- }
+
gen_set_access_type(ctx, ACCESS_INT);
EA = tcg_temp_new();
gen_addr_imm_index(ctx, EA, 0x0F);
- gen_qemu_ld64(ctx, cpu_gpr[rd], EA);
- gen_addr_add(ctx, EA, EA, 8);
- gen_qemu_ld64(ctx, cpu_gpr[rd+1], EA);
+
+ if (unlikely(ctx->le_mode)) {
+ gen_qemu_ld64(ctx, cpu_gpr[rd+1], EA);
+ gen_addr_add(ctx, EA, EA, 8);
+ gen_qemu_ld64(ctx, cpu_gpr[rd], EA);
+ } else {
+ gen_qemu_ld64(ctx, cpu_gpr[rd], EA);
+ gen_addr_add(ctx, EA, EA, 8);
+ gen_qemu_ld64(ctx, cpu_gpr[rd+1], EA);
+ }
tcg_temp_free(EA);
-#endif
}
#endif
@@ -2871,34 +2997,41 @@ static void gen_std(DisasContext *ctx)
TCGv EA;
rs = rS(ctx->opcode);
- if ((ctx->opcode & 0x3) == 0x2) {
-#if defined(CONFIG_USER_ONLY)
- gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
-#else
- /* stq */
- if (unlikely(ctx->mem_idx == 0)) {
+ if ((ctx->opcode & 0x3) == 0x2) { /* stq */
+
+ bool legal_in_user_mode = (ctx->insns_flags2 & PPC2_LSQ_ISA207) != 0;
+ bool le_is_supported = (ctx->insns_flags2 & PPC2_LSQ_ISA207) != 0;
+
+ if (!legal_in_user_mode && is_user_mode(ctx)) {
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC);
return;
}
- if (unlikely(rs & 1)) {
- gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+
+ if (!le_is_supported && ctx->le_mode) {
+ gen_exception_err(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE);
return;
}
- if (unlikely(ctx->le_mode)) {
- /* Little-endian mode is not handled */
- gen_exception_err(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE);
+
+ if (unlikely(rs & 1)) {
+ gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
return;
}
gen_set_access_type(ctx, ACCESS_INT);
EA = tcg_temp_new();
gen_addr_imm_index(ctx, EA, 0x03);
- gen_qemu_st64(ctx, cpu_gpr[rs], EA);
- gen_addr_add(ctx, EA, EA, 8);
- gen_qemu_st64(ctx, cpu_gpr[rs+1], EA);
+
+ if (unlikely(ctx->le_mode)) {
+ gen_qemu_st64(ctx, cpu_gpr[rs+1], EA);
+ gen_addr_add(ctx, EA, EA, 8);
+ gen_qemu_st64(ctx, cpu_gpr[rs], EA);
+ } else {
+ gen_qemu_st64(ctx, cpu_gpr[rs], EA);
+ gen_addr_add(ctx, EA, EA, 8);
+ gen_qemu_st64(ctx, cpu_gpr[rs+1], EA);
+ }
tcg_temp_free(EA);
-#endif
} else {
- /* std / stdu */
+ /* std / stdu*/
if (Rc(ctx->opcode)) {
if (unlikely(rA(ctx->opcode) == 0)) {
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
@@ -3140,24 +3273,32 @@ static void gen_isync(DisasContext *ctx)
gen_stop_exception(ctx);
}
-/* lwarx */
-static void gen_lwarx(DisasContext *ctx)
-{
- TCGv t0;
- TCGv gpr = cpu_gpr[rD(ctx->opcode)];
- gen_set_access_type(ctx, ACCESS_RES);
- t0 = tcg_temp_local_new();
- gen_addr_reg_index(ctx, t0);
- gen_check_align(ctx, t0, 0x03);
- gen_qemu_ld32u(ctx, gpr, t0);
- tcg_gen_mov_tl(cpu_reserve, t0);
- tcg_gen_st_tl(gpr, cpu_env, offsetof(CPUPPCState, reserve_val));
- tcg_temp_free(t0);
+#define LARX(name, len, loadop) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ TCGv t0; \
+ TCGv gpr = cpu_gpr[rD(ctx->opcode)]; \
+ gen_set_access_type(ctx, ACCESS_RES); \
+ t0 = tcg_temp_local_new(); \
+ gen_addr_reg_index(ctx, t0); \
+ if ((len) > 1) { \
+ gen_check_align(ctx, t0, (len)-1); \
+ } \
+ gen_qemu_##loadop(ctx, gpr, t0); \
+ tcg_gen_mov_tl(cpu_reserve, t0); \
+ tcg_gen_st_tl(gpr, cpu_env, offsetof(CPUPPCState, reserve_val)); \
+ tcg_temp_free(t0); \
}
+/* lwarx */
+LARX(lbarx, 1, ld8u);
+LARX(lharx, 2, ld16u);
+LARX(lwarx, 4, ld32u);
+
+
#if defined(CONFIG_USER_ONLY)
-static void gen_conditional_store (DisasContext *ctx, TCGv EA,
- int reg, int size)
+static void gen_conditional_store(DisasContext *ctx, TCGv EA,
+ int reg, int size)
{
TCGv t0 = tcg_temp_new();
uint32_t save_exception = ctx->exception;
@@ -3171,74 +3312,115 @@ static void gen_conditional_store (DisasContext *ctx, TCGv EA,
gen_exception(ctx, POWERPC_EXCP_STCX);
ctx->exception = save_exception;
}
-#endif
-
-/* stwcx. */
-static void gen_stwcx_(DisasContext *ctx)
-{
- TCGv t0;
- gen_set_access_type(ctx, ACCESS_RES);
- t0 = tcg_temp_local_new();
- gen_addr_reg_index(ctx, t0);
- gen_check_align(ctx, t0, 0x03);
-#if defined(CONFIG_USER_ONLY)
- gen_conditional_store(ctx, t0, rS(ctx->opcode), 4);
#else
- {
- int l1;
+static void gen_conditional_store(DisasContext *ctx, TCGv EA,
+ int reg, int size)
+{
+ int l1;
- tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so);
- l1 = gen_new_label();
- tcg_gen_brcond_tl(TCG_COND_NE, t0, cpu_reserve, l1);
- tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ);
- gen_qemu_st32(ctx, cpu_gpr[rS(ctx->opcode)], t0);
- gen_set_label(l1);
- tcg_gen_movi_tl(cpu_reserve, -1);
+ tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so);
+ l1 = gen_new_label();
+ tcg_gen_brcond_tl(TCG_COND_NE, EA, cpu_reserve, l1);
+ tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ);
+#if defined(TARGET_PPC64)
+ if (size == 8) {
+ gen_qemu_st64(ctx, cpu_gpr[reg], EA);
+ } else
+#endif
+ if (size == 4) {
+ gen_qemu_st32(ctx, cpu_gpr[reg], EA);
+ } else if (size == 2) {
+ gen_qemu_st16(ctx, cpu_gpr[reg], EA);
+#if defined(TARGET_PPC64)
+ } else if (size == 16) {
+ TCGv gpr1, gpr2 , EA8;
+ if (unlikely(ctx->le_mode)) {
+ gpr1 = cpu_gpr[reg+1];
+ gpr2 = cpu_gpr[reg];
+ } else {
+ gpr1 = cpu_gpr[reg];
+ gpr2 = cpu_gpr[reg+1];
+ }
+ gen_qemu_st64(ctx, gpr1, EA);
+ EA8 = tcg_temp_local_new();
+ gen_addr_add(ctx, EA8, EA, 8);
+ gen_qemu_st64(ctx, gpr2, EA8);
+ tcg_temp_free(EA8);
+#endif
+ } else {
+ gen_qemu_st8(ctx, cpu_gpr[reg], EA);
}
+ gen_set_label(l1);
+ tcg_gen_movi_tl(cpu_reserve, -1);
+}
#endif
- tcg_temp_free(t0);
+
+#define STCX(name, len) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ TCGv t0; \
+ if (unlikely((len == 16) && (rD(ctx->opcode) & 1))) { \
+ gen_inval_exception(ctx, \
+ POWERPC_EXCP_INVAL_INVAL); \
+ return; \
+ } \
+ gen_set_access_type(ctx, ACCESS_RES); \
+ t0 = tcg_temp_local_new(); \
+ gen_addr_reg_index(ctx, t0); \
+ if (len > 1) { \
+ gen_check_align(ctx, t0, (len)-1); \
+ } \
+ gen_conditional_store(ctx, t0, rS(ctx->opcode), len); \
+ tcg_temp_free(t0); \
}
+STCX(stbcx_, 1);
+STCX(sthcx_, 2);
+STCX(stwcx_, 4);
+
#if defined(TARGET_PPC64)
/* ldarx */
-static void gen_ldarx(DisasContext *ctx)
-{
- TCGv t0;
- TCGv gpr = cpu_gpr[rD(ctx->opcode)];
- gen_set_access_type(ctx, ACCESS_RES);
- t0 = tcg_temp_local_new();
- gen_addr_reg_index(ctx, t0);
- gen_check_align(ctx, t0, 0x07);
- gen_qemu_ld64(ctx, gpr, t0);
- tcg_gen_mov_tl(cpu_reserve, t0);
- tcg_gen_st_tl(gpr, cpu_env, offsetof(CPUPPCState, reserve_val));
- tcg_temp_free(t0);
-}
+LARX(ldarx, 8, ld64);
-/* stdcx. */
-static void gen_stdcx_(DisasContext *ctx)
+/* lqarx */
+static void gen_lqarx(DisasContext *ctx)
{
- TCGv t0;
+ TCGv EA;
+ int rd = rD(ctx->opcode);
+ TCGv gpr1, gpr2;
+
+ if (unlikely((rd & 1) || (rd == rA(ctx->opcode)) ||
+ (rd == rB(ctx->opcode)))) {
+ gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
+ return;
+ }
+
gen_set_access_type(ctx, ACCESS_RES);
- t0 = tcg_temp_local_new();
- gen_addr_reg_index(ctx, t0);
- gen_check_align(ctx, t0, 0x07);
-#if defined(CONFIG_USER_ONLY)
- gen_conditional_store(ctx, t0, rS(ctx->opcode), 8);
-#else
- {
- int l1;
- tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so);
- l1 = gen_new_label();
- tcg_gen_brcond_tl(TCG_COND_NE, t0, cpu_reserve, l1);
- tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], 1 << CRF_EQ);
- gen_qemu_st64(ctx, cpu_gpr[rS(ctx->opcode)], t0);
- gen_set_label(l1);
- tcg_gen_movi_tl(cpu_reserve, -1);
+ EA = tcg_temp_local_new();
+ gen_addr_reg_index(ctx, EA);
+ gen_check_align(ctx, EA, 15);
+ if (unlikely(ctx->le_mode)) {
+ gpr1 = cpu_gpr[rd+1];
+ gpr2 = cpu_gpr[rd];
+ } else {
+ gpr1 = cpu_gpr[rd];
+ gpr2 = cpu_gpr[rd+1];
}
-#endif
- tcg_temp_free(t0);
+ gen_qemu_ld64(ctx, gpr1, EA);
+ tcg_gen_mov_tl(cpu_reserve, EA);
+
+ gen_addr_add(ctx, EA, EA, 8);
+ gen_qemu_ld64(ctx, gpr2, EA);
+
+ tcg_gen_st_tl(gpr1, cpu_env, offsetof(CPUPPCState, reserve_val));
+ tcg_gen_st_tl(gpr2, cpu_env, offsetof(CPUPPCState, reserve_val2));
+
+ tcg_temp_free(EA);
}
+
+/* stdcx. */
+STCX(stdcx_, 8);
+STCX(stqcx_, 16);
#endif /* defined(TARGET_PPC64) */
/* sync */
@@ -3415,6 +3597,20 @@ static void gen_lfiwax(DisasContext *ctx)
tcg_temp_free(t0);
}
+/* lfiwzx */
+static void gen_lfiwzx(DisasContext *ctx)
+{
+ TCGv EA;
+ if (unlikely(!ctx->fpu_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_FPU);
+ return;
+ }
+ gen_set_access_type(ctx, ACCESS_FLOAT);
+ EA = tcg_temp_new();
+ gen_addr_reg_index(ctx, EA);
+ gen_qemu_ld32u_i64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
+ tcg_temp_free(EA);
+}
/*** Floating-point store ***/
#define GEN_STF(name, stop, opc, type) \
static void glue(gen_, name)(DisasContext *ctx) \
@@ -3638,6 +3834,7 @@ static void gen_b(DisasContext *ctx)
#define BCOND_IM 0
#define BCOND_LR 1
#define BCOND_CTR 2
+#define BCOND_TAR 3
static inline void gen_bcond(DisasContext *ctx, int type)
{
@@ -3646,10 +3843,12 @@ static inline void gen_bcond(DisasContext *ctx, int type)
TCGv target;
ctx->exception = POWERPC_EXCP_BRANCH;
- if (type == BCOND_LR || type == BCOND_CTR) {
+ if (type == BCOND_LR || type == BCOND_CTR || type == BCOND_TAR) {
target = tcg_temp_local_new();
if (type == BCOND_CTR)
tcg_gen_mov_tl(target, cpu_ctr);
+ else if (type == BCOND_TAR)
+ gen_load_spr(target, SPR_TAR);
else
tcg_gen_mov_tl(target, cpu_lr);
} else {
@@ -3731,6 +3930,11 @@ static void gen_bclr(DisasContext *ctx)
gen_bcond(ctx, BCOND_LR);
}
+static void gen_bctar(DisasContext *ctx)
+{
+ gen_bcond(ctx, BCOND_TAR);
+}
+
/*** Condition register logical ***/
#define GEN_CRLOGIC(name, tcg_op, opc) \
static void glue(gen_, name)(DisasContext *ctx) \
@@ -6650,6 +6854,9 @@ GEN_VX_LOGICAL(vandc, tcg_gen_andc_i64, 2, 17);
GEN_VX_LOGICAL(vor, tcg_gen_or_i64, 2, 18);
GEN_VX_LOGICAL(vxor, tcg_gen_xor_i64, 2, 19);
GEN_VX_LOGICAL(vnor, tcg_gen_nor_i64, 2, 20);
+GEN_VX_LOGICAL(veqv, tcg_gen_eqv_i64, 2, 26);
+GEN_VX_LOGICAL(vnand, tcg_gen_nand_i64, 2, 22);
+GEN_VX_LOGICAL(vorc, tcg_gen_orc_i64, 2, 21);
#define GEN_VXFORM(name, opc2, opc3) \
static void glue(gen_, name)(DisasContext *ctx) \
@@ -6685,24 +6892,69 @@ static void glue(gen_, name)(DisasContext *ctx) \
tcg_temp_free_ptr(rd); \
}
+#define GEN_VXFORM3(name, opc2, opc3) \
+static void glue(gen_, name)(DisasContext *ctx) \
+{ \
+ TCGv_ptr ra, rb, rc, rd; \
+ if (unlikely(!ctx->altivec_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VPU); \
+ return; \
+ } \
+ ra = gen_avr_ptr(rA(ctx->opcode)); \
+ rb = gen_avr_ptr(rB(ctx->opcode)); \
+ rc = gen_avr_ptr(rC(ctx->opcode)); \
+ rd = gen_avr_ptr(rD(ctx->opcode)); \
+ gen_helper_##name(rd, ra, rb, rc); \
+ tcg_temp_free_ptr(ra); \
+ tcg_temp_free_ptr(rb); \
+ tcg_temp_free_ptr(rc); \
+ tcg_temp_free_ptr(rd); \
+}
+
+/*
+ * Support for Altivec instruction pairs that use bit 31 (Rc) as
+ * an opcode bit. In general, these pairs come from different
+ * versions of the ISA, so we must also support a pair of flags for
+ * each instruction.
+ */
+#define GEN_VXFORM_DUAL(name0, flg0, flg2_0, name1, flg1, flg2_1) \
+static void glue(gen_, name0##_##name1)(DisasContext *ctx) \
+{ \
+ if ((Rc(ctx->opcode) == 0) && \
+ ((ctx->insns_flags & flg0) || (ctx->insns_flags2 & flg2_0))) { \
+ gen_##name0(ctx); \
+ } else if ((Rc(ctx->opcode) == 1) && \
+ ((ctx->insns_flags & flg1) || (ctx->insns_flags2 & flg2_1))) { \
+ gen_##name1(ctx); \
+ } else { \
+ gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \
+ } \
+}
+
GEN_VXFORM(vaddubm, 0, 0);
GEN_VXFORM(vadduhm, 0, 1);
GEN_VXFORM(vadduwm, 0, 2);
+GEN_VXFORM(vaddudm, 0, 3);
GEN_VXFORM(vsububm, 0, 16);
GEN_VXFORM(vsubuhm, 0, 17);
GEN_VXFORM(vsubuwm, 0, 18);
+GEN_VXFORM(vsubudm, 0, 19);
GEN_VXFORM(vmaxub, 1, 0);
GEN_VXFORM(vmaxuh, 1, 1);
GEN_VXFORM(vmaxuw, 1, 2);
+GEN_VXFORM(vmaxud, 1, 3);
GEN_VXFORM(vmaxsb, 1, 4);
GEN_VXFORM(vmaxsh, 1, 5);
GEN_VXFORM(vmaxsw, 1, 6);
+GEN_VXFORM(vmaxsd, 1, 7);
GEN_VXFORM(vminub, 1, 8);
GEN_VXFORM(vminuh, 1, 9);
GEN_VXFORM(vminuw, 1, 10);
+GEN_VXFORM(vminud, 1, 11);
GEN_VXFORM(vminsb, 1, 12);
GEN_VXFORM(vminsh, 1, 13);
GEN_VXFORM(vminsw, 1, 14);
+GEN_VXFORM(vminsd, 1, 15);
GEN_VXFORM(vavgub, 1, 16);
GEN_VXFORM(vavguh, 1, 17);
GEN_VXFORM(vavguw, 1, 18);
@@ -6715,23 +6967,68 @@ GEN_VXFORM(vmrghw, 6, 2);
GEN_VXFORM(vmrglb, 6, 4);
GEN_VXFORM(vmrglh, 6, 5);
GEN_VXFORM(vmrglw, 6, 6);
+
+static void gen_vmrgew(DisasContext *ctx)
+{
+ TCGv_i64 tmp;
+ int VT, VA, VB;
+ if (unlikely(!ctx->altivec_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_VPU);
+ return;
+ }
+ VT = rD(ctx->opcode);
+ VA = rA(ctx->opcode);
+ VB = rB(ctx->opcode);
+ tmp = tcg_temp_new_i64();
+ tcg_gen_shri_i64(tmp, cpu_avrh[VB], 32);
+ tcg_gen_deposit_i64(cpu_avrh[VT], cpu_avrh[VA], tmp, 0, 32);
+ tcg_gen_shri_i64(tmp, cpu_avrl[VB], 32);
+ tcg_gen_deposit_i64(cpu_avrl[VT], cpu_avrl[VA], tmp, 0, 32);
+ tcg_temp_free_i64(tmp);
+}
+
+static void gen_vmrgow(DisasContext *ctx)
+{
+ int VT, VA, VB;
+ if (unlikely(!ctx->altivec_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_VPU);
+ return;
+ }
+ VT = rD(ctx->opcode);
+ VA = rA(ctx->opcode);
+ VB = rB(ctx->opcode);
+
+ tcg_gen_deposit_i64(cpu_avrh[VT], cpu_avrh[VB], cpu_avrh[VA], 32, 32);
+ tcg_gen_deposit_i64(cpu_avrl[VT], cpu_avrl[VB], cpu_avrl[VA], 32, 32);
+}
+
GEN_VXFORM(vmuloub, 4, 0);
GEN_VXFORM(vmulouh, 4, 1);
+GEN_VXFORM(vmulouw, 4, 2);
+GEN_VXFORM(vmuluwm, 4, 2);
+GEN_VXFORM_DUAL(vmulouw, PPC_ALTIVEC, PPC_NONE,
+ vmuluwm, PPC_NONE, PPC2_ALTIVEC_207)
GEN_VXFORM(vmulosb, 4, 4);
GEN_VXFORM(vmulosh, 4, 5);
+GEN_VXFORM(vmulosw, 4, 6);
GEN_VXFORM(vmuleub, 4, 8);
GEN_VXFORM(vmuleuh, 4, 9);
+GEN_VXFORM(vmuleuw, 4, 10);
GEN_VXFORM(vmulesb, 4, 12);
GEN_VXFORM(vmulesh, 4, 13);
+GEN_VXFORM(vmulesw, 4, 14);
GEN_VXFORM(vslb, 2, 4);
GEN_VXFORM(vslh, 2, 5);
GEN_VXFORM(vslw, 2, 6);
+GEN_VXFORM(vsld, 2, 23);
GEN_VXFORM(vsrb, 2, 8);
GEN_VXFORM(vsrh, 2, 9);
GEN_VXFORM(vsrw, 2, 10);
+GEN_VXFORM(vsrd, 2, 27);
GEN_VXFORM(vsrab, 2, 12);
GEN_VXFORM(vsrah, 2, 13);
GEN_VXFORM(vsraw, 2, 14);
+GEN_VXFORM(vsrad, 2, 15);
GEN_VXFORM(vslo, 6, 16);
GEN_VXFORM(vsro, 6, 17);
GEN_VXFORM(vaddcuw, 0, 6);
@@ -6748,19 +7045,36 @@ GEN_VXFORM_ENV(vsubuws, 0, 26);
GEN_VXFORM_ENV(vsubsbs, 0, 28);
GEN_VXFORM_ENV(vsubshs, 0, 29);
GEN_VXFORM_ENV(vsubsws, 0, 30);
+GEN_VXFORM(vadduqm, 0, 4);
+GEN_VXFORM(vaddcuq, 0, 5);
+GEN_VXFORM3(vaddeuqm, 30, 0);
+GEN_VXFORM3(vaddecuq, 30, 0);
+GEN_VXFORM_DUAL(vaddeuqm, PPC_NONE, PPC2_ALTIVEC_207, \
+ vaddecuq, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXFORM(vsubuqm, 0, 20);
+GEN_VXFORM(vsubcuq, 0, 21);
+GEN_VXFORM3(vsubeuqm, 31, 0);
+GEN_VXFORM3(vsubecuq, 31, 0);
+GEN_VXFORM_DUAL(vsubeuqm, PPC_NONE, PPC2_ALTIVEC_207, \
+ vsubecuq, PPC_NONE, PPC2_ALTIVEC_207)
GEN_VXFORM(vrlb, 2, 0);
GEN_VXFORM(vrlh, 2, 1);
GEN_VXFORM(vrlw, 2, 2);
+GEN_VXFORM(vrld, 2, 3);
GEN_VXFORM(vsl, 2, 7);
GEN_VXFORM(vsr, 2, 11);
GEN_VXFORM_ENV(vpkuhum, 7, 0);
GEN_VXFORM_ENV(vpkuwum, 7, 1);
+GEN_VXFORM_ENV(vpkudum, 7, 17);
GEN_VXFORM_ENV(vpkuhus, 7, 2);
GEN_VXFORM_ENV(vpkuwus, 7, 3);
+GEN_VXFORM_ENV(vpkudus, 7, 19);
GEN_VXFORM_ENV(vpkshus, 7, 4);
GEN_VXFORM_ENV(vpkswus, 7, 5);
+GEN_VXFORM_ENV(vpksdus, 7, 21);
GEN_VXFORM_ENV(vpkshss, 7, 6);
GEN_VXFORM_ENV(vpkswss, 7, 7);
+GEN_VXFORM_ENV(vpksdss, 7, 23);
GEN_VXFORM(vpkpx, 7, 12);
GEN_VXFORM_ENV(vsum4ubs, 4, 24);
GEN_VXFORM_ENV(vsum4sbs, 4, 28);
@@ -6793,20 +7107,58 @@ static void glue(gen_, name)(DisasContext *ctx) \
GEN_VXRFORM1(name, name, #name, opc2, opc3) \
GEN_VXRFORM1(name##_dot, name##_, #name ".", opc2, (opc3 | (0x1 << 4)))
+/*
+ * Support for Altivec instructions that use bit 31 (Rc) as an opcode
+ * bit but also use bit 21 as an actual Rc bit. In general, thse pairs
+ * come from different versions of the ISA, so we must also support a
+ * pair of flags for each instruction.
+ */
+#define GEN_VXRFORM_DUAL(name0, flg0, flg2_0, name1, flg1, flg2_1) \
+static void glue(gen_, name0##_##name1)(DisasContext *ctx) \
+{ \
+ if ((Rc(ctx->opcode) == 0) && \
+ ((ctx->insns_flags & flg0) || (ctx->insns_flags2 & flg2_0))) { \
+ if (Rc21(ctx->opcode) == 0) { \
+ gen_##name0(ctx); \
+ } else { \
+ gen_##name0##_(ctx); \
+ } \
+ } else if ((Rc(ctx->opcode) == 1) && \
+ ((ctx->insns_flags & flg1) || (ctx->insns_flags2 & flg2_1))) { \
+ if (Rc21(ctx->opcode) == 0) { \
+ gen_##name1(ctx); \
+ } else { \
+ gen_##name1##_(ctx); \
+ } \
+ } else { \
+ gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL); \
+ } \
+}
+
GEN_VXRFORM(vcmpequb, 3, 0)
GEN_VXRFORM(vcmpequh, 3, 1)
GEN_VXRFORM(vcmpequw, 3, 2)
+GEN_VXRFORM(vcmpequd, 3, 3)
GEN_VXRFORM(vcmpgtsb, 3, 12)
GEN_VXRFORM(vcmpgtsh, 3, 13)
GEN_VXRFORM(vcmpgtsw, 3, 14)
+GEN_VXRFORM(vcmpgtsd, 3, 15)
GEN_VXRFORM(vcmpgtub, 3, 8)
GEN_VXRFORM(vcmpgtuh, 3, 9)
GEN_VXRFORM(vcmpgtuw, 3, 10)
+GEN_VXRFORM(vcmpgtud, 3, 11)
GEN_VXRFORM(vcmpeqfp, 3, 3)
GEN_VXRFORM(vcmpgefp, 3, 7)
GEN_VXRFORM(vcmpgtfp, 3, 11)
GEN_VXRFORM(vcmpbfp, 3, 15)
+GEN_VXRFORM_DUAL(vcmpeqfp, PPC_ALTIVEC, PPC_NONE, \
+ vcmpequd, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXRFORM_DUAL(vcmpbfp, PPC_ALTIVEC, PPC_NONE, \
+ vcmpgtsd, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXRFORM_DUAL(vcmpgtfp, PPC_ALTIVEC, PPC_NONE, \
+ vcmpgtud, PPC_NONE, PPC2_ALTIVEC_207)
+
#define GEN_VXFORM_SIMM(name, opc2, opc3) \
static void glue(gen_, name)(DisasContext *ctx) \
{ \
@@ -6860,8 +7212,10 @@ static void glue(gen_, name)(DisasContext *ctx) \
GEN_VXFORM_NOA(vupkhsb, 7, 8);
GEN_VXFORM_NOA(vupkhsh, 7, 9);
+GEN_VXFORM_NOA(vupkhsw, 7, 25);
GEN_VXFORM_NOA(vupklsb, 7, 10);
GEN_VXFORM_NOA(vupklsh, 7, 11);
+GEN_VXFORM_NOA(vupklsw, 7, 27);
GEN_VXFORM_NOA(vupkhpx, 7, 13);
GEN_VXFORM_NOA(vupklpx, 7, 15);
GEN_VXFORM_NOA_ENV(vrefp, 5, 4);
@@ -7002,6 +7356,115 @@ GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20)
GEN_VAFORM_PAIRED(vsel, vperm, 21)
GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23)
+GEN_VXFORM_NOA(vclzb, 1, 28)
+GEN_VXFORM_NOA(vclzh, 1, 29)
+GEN_VXFORM_NOA(vclzw, 1, 30)
+GEN_VXFORM_NOA(vclzd, 1, 31)
+GEN_VXFORM_NOA(vpopcntb, 1, 28)
+GEN_VXFORM_NOA(vpopcnth, 1, 29)
+GEN_VXFORM_NOA(vpopcntw, 1, 30)
+GEN_VXFORM_NOA(vpopcntd, 1, 31)
+GEN_VXFORM_DUAL(vclzb, PPC_NONE, PPC2_ALTIVEC_207, \
+ vpopcntb, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXFORM_DUAL(vclzh, PPC_NONE, PPC2_ALTIVEC_207, \
+ vpopcnth, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXFORM_DUAL(vclzw, PPC_NONE, PPC2_ALTIVEC_207, \
+ vpopcntw, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXFORM_DUAL(vclzd, PPC_NONE, PPC2_ALTIVEC_207, \
+ vpopcntd, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXFORM(vbpermq, 6, 21);
+GEN_VXFORM_NOA(vgbbd, 6, 20);
+GEN_VXFORM(vpmsumb, 4, 16)
+GEN_VXFORM(vpmsumh, 4, 17)
+GEN_VXFORM(vpmsumw, 4, 18)
+GEN_VXFORM(vpmsumd, 4, 19)
+
+#define GEN_BCD(op) \
+static void gen_##op(DisasContext *ctx) \
+{ \
+ TCGv_ptr ra, rb, rd; \
+ TCGv_i32 ps; \
+ \
+ if (unlikely(!ctx->altivec_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VPU); \
+ return; \
+ } \
+ \
+ ra = gen_avr_ptr(rA(ctx->opcode)); \
+ rb = gen_avr_ptr(rB(ctx->opcode)); \
+ rd = gen_avr_ptr(rD(ctx->opcode)); \
+ \
+ ps = tcg_const_i32((ctx->opcode & 0x200) != 0); \
+ \
+ gen_helper_##op(cpu_crf[6], rd, ra, rb, ps); \
+ \
+ tcg_temp_free_ptr(ra); \
+ tcg_temp_free_ptr(rb); \
+ tcg_temp_free_ptr(rd); \
+ tcg_temp_free_i32(ps); \
+}
+
+GEN_BCD(bcdadd)
+GEN_BCD(bcdsub)
+
+GEN_VXFORM_DUAL(vsububm, PPC_ALTIVEC, PPC_NONE, \
+ bcdadd, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXFORM_DUAL(vsububs, PPC_ALTIVEC, PPC_NONE, \
+ bcdadd, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXFORM_DUAL(vsubuhm, PPC_ALTIVEC, PPC_NONE, \
+ bcdsub, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXFORM_DUAL(vsubuhs, PPC_ALTIVEC, PPC_NONE, \
+ bcdsub, PPC_NONE, PPC2_ALTIVEC_207)
+
+static void gen_vsbox(DisasContext *ctx)
+{
+ TCGv_ptr ra, rd;
+ if (unlikely(!ctx->altivec_enabled)) {
+ gen_exception(ctx, POWERPC_EXCP_VPU);
+ return;
+ }
+ ra = gen_avr_ptr(rA(ctx->opcode));
+ rd = gen_avr_ptr(rD(ctx->opcode));
+ gen_helper_vsbox(rd, ra);
+ tcg_temp_free_ptr(ra);
+ tcg_temp_free_ptr(rd);
+}
+
+GEN_VXFORM(vcipher, 4, 20)
+GEN_VXFORM(vcipherlast, 4, 20)
+GEN_VXFORM(vncipher, 4, 21)
+GEN_VXFORM(vncipherlast, 4, 21)
+
+GEN_VXFORM_DUAL(vcipher, PPC_NONE, PPC2_ALTIVEC_207,
+ vcipherlast, PPC_NONE, PPC2_ALTIVEC_207)
+GEN_VXFORM_DUAL(vncipher, PPC_NONE, PPC2_ALTIVEC_207,
+ vncipherlast, PPC_NONE, PPC2_ALTIVEC_207)
+
+#define VSHASIGMA(op) \
+static void gen_##op(DisasContext *ctx) \
+{ \
+ TCGv_ptr ra, rd; \
+ TCGv_i32 st_six; \
+ if (unlikely(!ctx->altivec_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VPU); \
+ return; \
+ } \
+ ra = gen_avr_ptr(rA(ctx->opcode)); \
+ rd = gen_avr_ptr(rD(ctx->opcode)); \
+ st_six = tcg_const_i32(rB(ctx->opcode)); \
+ gen_helper_##op(rd, ra, st_six); \
+ tcg_temp_free_ptr(ra); \
+ tcg_temp_free_ptr(rd); \
+ tcg_temp_free_i32(st_six); \
+}
+
+VSHASIGMA(vshasigmaw)
+VSHASIGMA(vshasigmad)
+
+GEN_VXFORM3(vpermxor, 22, 0xFF)
+GEN_VXFORM_DUAL(vsldoi, PPC_ALTIVEC, PPC_NONE,
+ vpermxor, PPC_NONE, PPC2_ALTIVEC_207)
+
/*** VSX extension ***/
static inline TCGv_i64 cpu_vsrh(int n)
@@ -7022,21 +7485,27 @@ static inline TCGv_i64 cpu_vsrl(int n)
}
}
-static void gen_lxsdx(DisasContext *ctx)
-{
- TCGv EA;
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
- }
- gen_set_access_type(ctx, ACCESS_INT);
- EA = tcg_temp_new();
- gen_addr_reg_index(ctx, EA);
- gen_qemu_ld64(ctx, cpu_vsrh(xT(ctx->opcode)), EA);
- /* NOTE: cpu_vsrl is undefined */
- tcg_temp_free(EA);
+#define VSX_LOAD_SCALAR(name, operation) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ TCGv EA; \
+ if (unlikely(!ctx->vsx_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VSXU); \
+ return; \
+ } \
+ gen_set_access_type(ctx, ACCESS_INT); \
+ EA = tcg_temp_new(); \
+ gen_addr_reg_index(ctx, EA); \
+ gen_qemu_##operation(ctx, cpu_vsrh(xT(ctx->opcode)), EA); \
+ /* NOTE: cpu_vsrl is undefined */ \
+ tcg_temp_free(EA); \
}
+VSX_LOAD_SCALAR(lxsdx, ld64)
+VSX_LOAD_SCALAR(lxsiwax, ld32s_i64)
+VSX_LOAD_SCALAR(lxsiwzx, ld32u_i64)
+VSX_LOAD_SCALAR(lxsspx, ld32fs)
+
static void gen_lxvd2x(DisasContext *ctx)
{
TCGv EA;
@@ -7098,20 +7567,25 @@ static void gen_lxvw4x(DisasContext *ctx)
tcg_temp_free_i64(tmp);
}
-static void gen_stxsdx(DisasContext *ctx)
-{
- TCGv EA;
- if (unlikely(!ctx->vsx_enabled)) {
- gen_exception(ctx, POWERPC_EXCP_VSXU);
- return;
- }
- gen_set_access_type(ctx, ACCESS_INT);
- EA = tcg_temp_new();
- gen_addr_reg_index(ctx, EA);
- gen_qemu_st64(ctx, cpu_vsrh(xS(ctx->opcode)), EA);
- tcg_temp_free(EA);
+#define VSX_STORE_SCALAR(name, operation) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ TCGv EA; \
+ if (unlikely(!ctx->vsx_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VSXU); \
+ return; \
+ } \
+ gen_set_access_type(ctx, ACCESS_INT); \
+ EA = tcg_temp_new(); \
+ gen_addr_reg_index(ctx, EA); \
+ gen_qemu_##operation(ctx, cpu_vsrh(xS(ctx->opcode)), EA); \
+ tcg_temp_free(EA); \
}
+VSX_STORE_SCALAR(stxsdx, st64)
+VSX_STORE_SCALAR(stxsiwx, st32_i64)
+VSX_STORE_SCALAR(stxsspx, st32fs)
+
static void gen_stxvd2x(DisasContext *ctx)
{
TCGv EA;
@@ -7156,6 +7630,57 @@ static void gen_stxvw4x(DisasContext *ctx)
tcg_temp_free_i64(tmp);
}
+#define MV_VSRW(name, tcgop1, tcgop2, target, source) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ if (xS(ctx->opcode) < 32) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_FPU); \
+ return; \
+ } \
+ } else { \
+ if (unlikely(!ctx->altivec_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VPU); \
+ return; \
+ } \
+ } \
+ TCGv_i64 tmp = tcg_temp_new_i64(); \
+ tcg_gen_##tcgop1(tmp, source); \
+ tcg_gen_##tcgop2(target, tmp); \
+ tcg_temp_free_i64(tmp); \
+}
+
+
+MV_VSRW(mfvsrwz, ext32u_i64, trunc_i64_tl, cpu_gpr[rA(ctx->opcode)], \
+ cpu_vsrh(xS(ctx->opcode)))
+MV_VSRW(mtvsrwa, extu_tl_i64, ext32s_i64, cpu_vsrh(xT(ctx->opcode)), \
+ cpu_gpr[rA(ctx->opcode)])
+MV_VSRW(mtvsrwz, extu_tl_i64, ext32u_i64, cpu_vsrh(xT(ctx->opcode)), \
+ cpu_gpr[rA(ctx->opcode)])
+
+#if defined(TARGET_PPC64)
+#define MV_VSRD(name, target, source) \
+static void gen_##name(DisasContext *ctx) \
+{ \
+ if (xS(ctx->opcode) < 32) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_FPU); \
+ return; \
+ } \
+ } else { \
+ if (unlikely(!ctx->altivec_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VPU); \
+ return; \
+ } \
+ } \
+ tcg_gen_mov_i64(target, source); \
+}
+
+MV_VSRD(mfvsrd, cpu_gpr[rA(ctx->opcode)], cpu_vsrh(xS(ctx->opcode)))
+MV_VSRD(mtvsrd, cpu_vsrh(xT(ctx->opcode)), cpu_gpr[rA(ctx->opcode)])
+
+#endif
+
static void gen_xxpermdi(DisasContext *ctx)
{
if (unlikely(!ctx->vsx_enabled)) {
@@ -7163,15 +7688,40 @@ static void gen_xxpermdi(DisasContext *ctx)
return;
}
- if ((DM(ctx->opcode) & 2) == 0) {
- tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrh(xA(ctx->opcode)));
- } else {
- tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrl(xA(ctx->opcode)));
- }
- if ((DM(ctx->opcode) & 1) == 0) {
- tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xB(ctx->opcode)));
+ if (unlikely((xT(ctx->opcode) == xA(ctx->opcode)) ||
+ (xT(ctx->opcode) == xB(ctx->opcode)))) {
+ TCGv_i64 xh, xl;
+
+ xh = tcg_temp_new_i64();
+ xl = tcg_temp_new_i64();
+
+ if ((DM(ctx->opcode) & 2) == 0) {
+ tcg_gen_mov_i64(xh, cpu_vsrh(xA(ctx->opcode)));
+ } else {
+ tcg_gen_mov_i64(xh, cpu_vsrl(xA(ctx->opcode)));
+ }
+ if ((DM(ctx->opcode) & 1) == 0) {
+ tcg_gen_mov_i64(xl, cpu_vsrh(xB(ctx->opcode)));
+ } else {
+ tcg_gen_mov_i64(xl, cpu_vsrl(xB(ctx->opcode)));
+ }
+
+ tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), xh);
+ tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), xl);
+
+ tcg_temp_free_i64(xh);
+ tcg_temp_free_i64(xl);
} else {
- tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrl(xB(ctx->opcode)));
+ if ((DM(ctx->opcode) & 2) == 0) {
+ tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrh(xA(ctx->opcode)));
+ } else {
+ tcg_gen_mov_i64(cpu_vsrh(xT(ctx->opcode)), cpu_vsrl(xA(ctx->opcode)));
+ }
+ if ((DM(ctx->opcode) & 1) == 0) {
+ tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrh(xB(ctx->opcode)));
+ } else {
+ tcg_gen_mov_i64(cpu_vsrl(xT(ctx->opcode)), cpu_vsrl(xB(ctx->opcode)));
+ }
}
}
@@ -7179,8 +7729,8 @@ static void gen_xxpermdi(DisasContext *ctx)
#define OP_NABS 2
#define OP_NEG 3
#define OP_CPSGN 4
-#define SGN_MASK_DP 0x8000000000000000ul
-#define SGN_MASK_SP 0x8000000080000000ul
+#define SGN_MASK_DP 0x8000000000000000ull
+#define SGN_MASK_SP 0x8000000080000000ull
#define VSX_SCALAR_MOVE(name, op, sgn_mask) \
static void glue(gen_, name)(DisasContext * ctx) \
@@ -7289,6 +7839,165 @@ VSX_VECTOR_MOVE(xvnabssp, OP_NABS, SGN_MASK_SP)
VSX_VECTOR_MOVE(xvnegsp, OP_NEG, SGN_MASK_SP)
VSX_VECTOR_MOVE(xvcpsgnsp, OP_CPSGN, SGN_MASK_SP)
+#define GEN_VSX_HELPER_2(name, op1, op2, inval, type) \
+static void gen_##name(DisasContext * ctx) \
+{ \
+ TCGv_i32 opc; \
+ if (unlikely(!ctx->vsx_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VSXU); \
+ return; \
+ } \
+ /* NIP cannot be restored if the memory exception comes from an helper */ \
+ gen_update_nip(ctx, ctx->nip - 4); \
+ opc = tcg_const_i32(ctx->opcode); \
+ gen_helper_##name(cpu_env, opc); \
+ tcg_temp_free_i32(opc); \
+}
+
+#define GEN_VSX_HELPER_XT_XB_ENV(name, op1, op2, inval, type) \
+static void gen_##name(DisasContext * ctx) \
+{ \
+ if (unlikely(!ctx->vsx_enabled)) { \
+ gen_exception(ctx, POWERPC_EXCP_VSXU); \
+ return; \
+ } \
+ /* NIP cannot be restored if the exception comes */ \
+ /* from a helper. */ \
+ gen_update_nip(ctx, ctx->nip - 4); \
+ \
+ gen_helper_##name(cpu_vsrh(xT(ctx->opcode)), cpu_env, \
+ cpu_vsrh(xB(ctx->opcode))); \
+}
+
+GEN_VSX_HELPER_2(xsadddp, 0x00, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xssubdp, 0x00, 0x05, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsmuldp, 0x00, 0x06, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsdivdp, 0x00, 0x07, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsredp, 0x14, 0x05, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xssqrtdp, 0x16, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsrsqrtedp, 0x14, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xstdivdp, 0x14, 0x07, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xstsqrtdp, 0x14, 0x06, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsmaddadp, 0x04, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsmaddmdp, 0x04, 0x05, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsmsubadp, 0x04, 0x06, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsmsubmdp, 0x04, 0x07, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsnmaddadp, 0x04, 0x14, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsnmaddmdp, 0x04, 0x15, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsnmsubadp, 0x04, 0x16, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsnmsubmdp, 0x04, 0x17, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xscmpodp, 0x0C, 0x05, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xscmpudp, 0x0C, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsmaxdp, 0x00, 0x14, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsmindp, 0x00, 0x15, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xscvdpsp, 0x12, 0x10, 0, PPC2_VSX)
+GEN_VSX_HELPER_XT_XB_ENV(xscvdpspn, 0x16, 0x10, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xscvspdp, 0x12, 0x14, 0, PPC2_VSX)
+GEN_VSX_HELPER_XT_XB_ENV(xscvspdpn, 0x16, 0x14, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xscvdpsxds, 0x10, 0x15, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xscvdpsxws, 0x10, 0x05, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xscvdpuxds, 0x10, 0x14, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xscvdpuxws, 0x10, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xscvsxddp, 0x10, 0x17, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xscvuxddp, 0x10, 0x16, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsrdpi, 0x12, 0x04, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsrdpic, 0x16, 0x06, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsrdpim, 0x12, 0x07, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsrdpip, 0x12, 0x06, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xsrdpiz, 0x12, 0x05, 0, PPC2_VSX)
+GEN_VSX_HELPER_XT_XB_ENV(xsrsp, 0x12, 0x11, 0, PPC2_VSX207)
+
+GEN_VSX_HELPER_2(xsaddsp, 0x00, 0x00, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xssubsp, 0x00, 0x01, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsmulsp, 0x00, 0x02, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsdivsp, 0x00, 0x03, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsresp, 0x14, 0x01, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xssqrtsp, 0x16, 0x00, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsrsqrtesp, 0x14, 0x00, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsmaddasp, 0x04, 0x00, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsmaddmsp, 0x04, 0x01, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsmsubasp, 0x04, 0x02, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsmsubmsp, 0x04, 0x03, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsnmaddasp, 0x04, 0x10, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsnmaddmsp, 0x04, 0x11, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsnmsubasp, 0x04, 0x12, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xsnmsubmsp, 0x04, 0x13, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xscvsxdsp, 0x10, 0x13, 0, PPC2_VSX207)
+GEN_VSX_HELPER_2(xscvuxdsp, 0x10, 0x12, 0, PPC2_VSX207)
+
+GEN_VSX_HELPER_2(xvadddp, 0x00, 0x0C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvsubdp, 0x00, 0x0D, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmuldp, 0x00, 0x0E, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvdivdp, 0x00, 0x0F, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvredp, 0x14, 0x0D, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvsqrtdp, 0x16, 0x0C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrsqrtedp, 0x14, 0x0C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvtdivdp, 0x14, 0x0F, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvtsqrtdp, 0x14, 0x0E, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmaddadp, 0x04, 0x0C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmaddmdp, 0x04, 0x0D, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmsubadp, 0x04, 0x0E, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmsubmdp, 0x04, 0x0F, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvnmaddadp, 0x04, 0x1C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvnmaddmdp, 0x04, 0x1D, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvnmsubadp, 0x04, 0x1E, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvnmsubmdp, 0x04, 0x1F, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmaxdp, 0x00, 0x1C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmindp, 0x00, 0x1D, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcmpeqdp, 0x0C, 0x0C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcmpgtdp, 0x0C, 0x0D, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcmpgedp, 0x0C, 0x0E, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvdpsp, 0x12, 0x18, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvdpsxds, 0x10, 0x1D, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvdpsxws, 0x10, 0x0D, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvdpuxds, 0x10, 0x1C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvdpuxws, 0x10, 0x0C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvsxddp, 0x10, 0x1F, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvuxddp, 0x10, 0x1E, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvsxwdp, 0x10, 0x0F, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvuxwdp, 0x10, 0x0E, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrdpi, 0x12, 0x0C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrdpic, 0x16, 0x0E, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrdpim, 0x12, 0x0F, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrdpip, 0x12, 0x0E, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrdpiz, 0x12, 0x0D, 0, PPC2_VSX)
+
+GEN_VSX_HELPER_2(xvaddsp, 0x00, 0x08, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvsubsp, 0x00, 0x09, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmulsp, 0x00, 0x0A, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvdivsp, 0x00, 0x0B, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvresp, 0x14, 0x09, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvsqrtsp, 0x16, 0x08, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrsqrtesp, 0x14, 0x08, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvtdivsp, 0x14, 0x0B, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvtsqrtsp, 0x14, 0x0A, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmaddasp, 0x04, 0x08, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmaddmsp, 0x04, 0x09, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmsubasp, 0x04, 0x0A, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmsubmsp, 0x04, 0x0B, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvnmaddasp, 0x04, 0x18, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvnmaddmsp, 0x04, 0x19, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvnmsubasp, 0x04, 0x1A, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvnmsubmsp, 0x04, 0x1B, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvmaxsp, 0x00, 0x18, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvminsp, 0x00, 0x19, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcmpeqsp, 0x0C, 0x08, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcmpgtsp, 0x0C, 0x09, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcmpgesp, 0x0C, 0x0A, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvspdp, 0x12, 0x1C, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvspsxds, 0x10, 0x19, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvspsxws, 0x10, 0x09, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvspuxds, 0x10, 0x18, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvspuxws, 0x10, 0x08, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvsxdsp, 0x10, 0x1B, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvuxdsp, 0x10, 0x1A, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvsxwsp, 0x10, 0x0B, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvcvuxwsp, 0x10, 0x0A, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrspi, 0x12, 0x08, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrspic, 0x16, 0x0A, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrspim, 0x12, 0x0B, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrspip, 0x12, 0x0A, 0, PPC2_VSX)
+GEN_VSX_HELPER_2(xvrspiz, 0x12, 0x09, 0, PPC2_VSX)
#define VSX_LOGICAL(name, tcg_op) \
static void glue(gen_, name)(DisasContext * ctx) \
@@ -7308,6 +8017,9 @@ VSX_LOGICAL(xxlandc, tcg_gen_andc_i64)
VSX_LOGICAL(xxlor, tcg_gen_or_i64)
VSX_LOGICAL(xxlxor, tcg_gen_xor_i64)
VSX_LOGICAL(xxlnor, tcg_gen_nor_i64)
+VSX_LOGICAL(xxleqv, tcg_gen_eqv_i64)
+VSX_LOGICAL(xxlnand, tcg_gen_nand_i64)
+VSX_LOGICAL(xxlorc, tcg_gen_orc_i64)
#define VSX_XXMRG(name, high) \
static void glue(gen_, name)(DisasContext * ctx) \
@@ -9175,6 +9887,7 @@ GEN_HANDLER_E(prtyw, 0x1F, 0x1A, 0x04, 0x0000F801, PPC_NONE, PPC2_ISA205),
GEN_HANDLER(popcntd, 0x1F, 0x1A, 0x0F, 0x0000F801, PPC_POPCNTWD),
GEN_HANDLER(cntlzd, 0x1F, 0x1A, 0x01, 0x00000000, PPC_64B),
GEN_HANDLER_E(prtyd, 0x1F, 0x1A, 0x05, 0x0000F801, PPC_NONE, PPC2_ISA205),
+GEN_HANDLER_E(bpermd, 0x1F, 0x1C, 0x07, 0x00000001, PPC_NONE, PPC2_PERM_ISA206),
#endif
GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
@@ -9200,6 +9913,8 @@ GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT),
GEN_HANDLER(fnabs, 0x3F, 0x08, 0x04, 0x001F0000, PPC_FLOAT),
GEN_HANDLER(fneg, 0x3F, 0x08, 0x01, 0x001F0000, PPC_FLOAT),
GEN_HANDLER_E(fcpsgn, 0x3F, 0x08, 0x00, 0x00000000, PPC_NONE, PPC2_ISA205),
+GEN_HANDLER_E(fmrgew, 0x3F, 0x06, 0x1E, 0x00000001, PPC_NONE, PPC2_VSX207),
+GEN_HANDLER_E(fmrgow, 0x3F, 0x06, 0x1A, 0x00000001, PPC_NONE, PPC2_VSX207),
GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT),
GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT),
GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT),
@@ -9219,11 +9934,17 @@ GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_STRING),
GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_STRING),
GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FFF801, PPC_MEM_EIEIO),
GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FFF801, PPC_MEM),
+GEN_HANDLER_E(lbarx, 0x1F, 0x14, 0x01, 0, PPC_NONE, PPC2_ATOMIC_ISA206),
+GEN_HANDLER_E(lharx, 0x1F, 0x14, 0x03, 0, PPC_NONE, PPC2_ATOMIC_ISA206),
GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000000, PPC_RES),
+GEN_HANDLER_E(stbcx_, 0x1F, 0x16, 0x15, 0, PPC_NONE, PPC2_ATOMIC_ISA206),
+GEN_HANDLER_E(sthcx_, 0x1F, 0x16, 0x16, 0, PPC_NONE, PPC2_ATOMIC_ISA206),
GEN_HANDLER2(stwcx_, "stwcx.", 0x1F, 0x16, 0x04, 0x00000000, PPC_RES),
#if defined(TARGET_PPC64)
GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000000, PPC_64B),
+GEN_HANDLER_E(lqarx, 0x1F, 0x14, 0x08, 0, PPC_NONE, PPC2_LSQ_ISA207),
GEN_HANDLER2(stdcx_, "stdcx.", 0x1F, 0x16, 0x06, 0x00000000, PPC_64B),
+GEN_HANDLER_E(stqcx_, 0x1F, 0x16, 0x05, 0, PPC_NONE, PPC2_LSQ_ISA207),
#endif
GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x039FF801, PPC_MEM_SYNC),
GEN_HANDLER(wait, 0x1F, 0x1E, 0x01, 0x03FFF801, PPC_WAIT),
@@ -9231,6 +9952,7 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW),
GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW),
GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW),
GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW),
+GEN_HANDLER_E(bctar, 0x13, 0x10, 0x11, 0, PPC_NONE, PPC2_BCTAR_ISA207),
GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER),
GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW),
#if defined(TARGET_PPC64)
@@ -9258,8 +9980,8 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC),
GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03C00001, PPC_CACHE),
GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE),
GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE),
-GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x02000001, PPC_CACHE),
-GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x02000001, PPC_CACHE),
+GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x00000001, PPC_CACHE),
+GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x00000001, PPC_CACHE),
GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03C00001, PPC_CACHE_DCBZ),
GEN_HANDLER(dst, 0x1F, 0x16, 0x0A, 0x01800001, PPC_ALTIVEC),
GEN_HANDLER(dstst, 0x1F, 0x16, 0x0B, 0x02000001, PPC_ALTIVEC),
@@ -9395,7 +10117,6 @@ GEN_HANDLER(lvsl, 0x1f, 0x06, 0x00, 0x00000001, PPC_ALTIVEC),
GEN_HANDLER(lvsr, 0x1f, 0x06, 0x01, 0x00000001, PPC_ALTIVEC),
GEN_HANDLER(mfvscr, 0x04, 0x2, 0x18, 0x001ff800, PPC_ALTIVEC),
GEN_HANDLER(mtvscr, 0x04, 0x2, 0x19, 0x03ff0000, PPC_ALTIVEC),
-GEN_HANDLER(vsldoi, 0x04, 0x16, 0xFF, 0x00000400, PPC_ALTIVEC),
GEN_HANDLER(vmladduhm, 0x04, 0x11, 0xFF, 0x00000000, PPC_ALTIVEC),
GEN_HANDLER2(evsel0, "evsel", 0x04, 0x1c, 0x09, 0x00000000, PPC_SPE),
GEN_HANDLER2(evsel1, "evsel", 0x04, 0x1d, 0x09, 0x00000000, PPC_SPE),
@@ -9427,6 +10148,10 @@ GEN_INT_ARITH_DIVW(divwu, 0x0E, 0, 0),
GEN_INT_ARITH_DIVW(divwuo, 0x1E, 0, 1),
GEN_INT_ARITH_DIVW(divw, 0x0F, 1, 0),
GEN_INT_ARITH_DIVW(divwo, 0x1F, 1, 1),
+GEN_HANDLER_E(divwe, 0x1F, 0x0B, 0x0D, 0, PPC_NONE, PPC2_DIVE_ISA206),
+GEN_HANDLER_E(divweo, 0x1F, 0x0B, 0x1D, 0, PPC_NONE, PPC2_DIVE_ISA206),
+GEN_HANDLER_E(divweu, 0x1F, 0x0B, 0x0C, 0, PPC_NONE, PPC2_DIVE_ISA206),
+GEN_HANDLER_E(divweuo, 0x1F, 0x0B, 0x1C, 0, PPC_NONE, PPC2_DIVE_ISA206),
#if defined(TARGET_PPC64)
#undef GEN_INT_ARITH_DIVD
@@ -9437,6 +10162,11 @@ GEN_INT_ARITH_DIVD(divduo, 0x1E, 0, 1),
GEN_INT_ARITH_DIVD(divd, 0x0F, 1, 0),
GEN_INT_ARITH_DIVD(divdo, 0x1F, 1, 1),
+GEN_HANDLER_E(divdeu, 0x1F, 0x09, 0x0C, 0, PPC_NONE, PPC2_DIVE_ISA206),
+GEN_HANDLER_E(divdeuo, 0x1F, 0x09, 0x1C, 0, PPC_NONE, PPC2_DIVE_ISA206),
+GEN_HANDLER_E(divde, 0x1F, 0x09, 0x0D, 0, PPC_NONE, PPC2_DIVE_ISA206),
+GEN_HANDLER_E(divdeo, 0x1F, 0x09, 0x1D, 0, PPC_NONE, PPC2_DIVE_ISA206),
+
#undef GEN_INT_ARITH_MUL_HELPER
#define GEN_INT_ARITH_MUL_HELPER(name, opc3) \
GEN_HANDLER(name, 0x1F, 0x09, opc3, 0x00000000, PPC_64B)
@@ -9544,13 +10274,22 @@ GEN_FLOAT_ACB(madd, 0x1D, 1, PPC_FLOAT),
GEN_FLOAT_ACB(msub, 0x1C, 1, PPC_FLOAT),
GEN_FLOAT_ACB(nmadd, 0x1F, 1, PPC_FLOAT),
GEN_FLOAT_ACB(nmsub, 0x1E, 1, PPC_FLOAT),
+GEN_HANDLER_E(ftdiv, 0x3F, 0x00, 0x04, 1, PPC_NONE, PPC2_FP_TST_ISA206),
+GEN_HANDLER_E(ftsqrt, 0x3F, 0x00, 0x05, 1, PPC_NONE, PPC2_FP_TST_ISA206),
GEN_FLOAT_B(ctiw, 0x0E, 0x00, 0, PPC_FLOAT),
+GEN_HANDLER_E(fctiwu, 0x3F, 0x0E, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
GEN_FLOAT_B(ctiwz, 0x0F, 0x00, 0, PPC_FLOAT),
+GEN_HANDLER_E(fctiwuz, 0x3F, 0x0F, 0x04, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
GEN_FLOAT_B(rsp, 0x0C, 0x00, 1, PPC_FLOAT),
#if defined(TARGET_PPC64)
GEN_FLOAT_B(cfid, 0x0E, 0x1A, 1, PPC_64B),
+GEN_HANDLER_E(fcfids, 0x3B, 0x0E, 0x1A, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
+GEN_HANDLER_E(fcfidu, 0x3F, 0x0E, 0x1E, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
+GEN_HANDLER_E(fcfidus, 0x3B, 0x0E, 0x1E, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
GEN_FLOAT_B(ctid, 0x0E, 0x19, 0, PPC_64B),
+GEN_HANDLER_E(fctidu, 0x3F, 0x0E, 0x1D, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
GEN_FLOAT_B(ctidz, 0x0F, 0x19, 0, PPC_64B),
+GEN_HANDLER_E(fctiduz, 0x3F, 0x0F, 0x1D, 0, PPC_NONE, PPC2_FP_CVT_ISA206),
#endif
GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT),
GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT),
@@ -9642,6 +10381,7 @@ GEN_LDXF(name, ldop, 0x17, op | 0x00, type)
GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT)
GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT)
GEN_HANDLER_E(lfiwax, 0x1f, 0x17, 0x1a, 0x00000001, PPC_NONE, PPC2_ISA205),
+GEN_HANDLER_E(lfiwzx, 0x1f, 0x17, 0x1b, 0x1, PPC_NONE, PPC2_FP_CVT_ISA206),
GEN_HANDLER_E(lfdp, 0x39, 0xFF, 0xFF, 0x00200003, PPC_NONE, PPC2_ISA205),
GEN_HANDLER_E(lfdpx, 0x1F, 0x17, 0x18, 0x00200001, PPC_NONE, PPC2_ISA205),
@@ -9754,33 +10494,61 @@ GEN_VR_STVE(wx, 0x07, 0x06),
#undef GEN_VX_LOGICAL
#define GEN_VX_LOGICAL(name, tcg_op, opc2, opc3) \
GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)
+
+#undef GEN_VX_LOGICAL_207
+#define GEN_VX_LOGICAL_207(name, tcg_op, opc2, opc3) \
+GEN_HANDLER_E(name, 0x04, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ALTIVEC_207)
+
GEN_VX_LOGICAL(vand, tcg_gen_and_i64, 2, 16),
GEN_VX_LOGICAL(vandc, tcg_gen_andc_i64, 2, 17),
GEN_VX_LOGICAL(vor, tcg_gen_or_i64, 2, 18),
GEN_VX_LOGICAL(vxor, tcg_gen_xor_i64, 2, 19),
GEN_VX_LOGICAL(vnor, tcg_gen_nor_i64, 2, 20),
+GEN_VX_LOGICAL_207(veqv, tcg_gen_eqv_i64, 2, 26),
+GEN_VX_LOGICAL_207(vnand, tcg_gen_nand_i64, 2, 22),
+GEN_VX_LOGICAL_207(vorc, tcg_gen_orc_i64, 2, 21),
#undef GEN_VXFORM
#define GEN_VXFORM(name, opc2, opc3) \
GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_ALTIVEC)
+
+#undef GEN_VXFORM_207
+#define GEN_VXFORM_207(name, opc2, opc3) \
+GEN_HANDLER_E(name, 0x04, opc2, opc3, 0x00000000, PPC_NONE, PPC2_ALTIVEC_207)
+
+#undef GEN_VXFORM_DUAL
+#define GEN_VXFORM_DUAL(name0, name1, opc2, opc3, type0, type1) \
+GEN_HANDLER_E(name0##_##name1, 0x4, opc2, opc3, 0x00000000, type0, type1)
+
+#undef GEN_VXRFORM_DUAL
+#define GEN_VXRFORM_DUAL(name0, name1, opc2, opc3, tp0, tp1) \
+GEN_HANDLER_E(name0##_##name1, 0x4, opc2, opc3, 0x00000000, tp0, tp1), \
+GEN_HANDLER_E(name0##_##name1, 0x4, opc2, (opc3 | 0x10), 0x00000000, tp0, tp1),
+
GEN_VXFORM(vaddubm, 0, 0),
GEN_VXFORM(vadduhm, 0, 1),
GEN_VXFORM(vadduwm, 0, 2),
-GEN_VXFORM(vsububm, 0, 16),
-GEN_VXFORM(vsubuhm, 0, 17),
+GEN_VXFORM_207(vaddudm, 0, 3),
+GEN_VXFORM_DUAL(vsububm, bcdadd, 0, 16, PPC_ALTIVEC, PPC_NONE),
+GEN_VXFORM_DUAL(vsubuhm, bcdsub, 0, 17, PPC_ALTIVEC, PPC_NONE),
GEN_VXFORM(vsubuwm, 0, 18),
+GEN_VXFORM_207(vsubudm, 0, 19),
GEN_VXFORM(vmaxub, 1, 0),
GEN_VXFORM(vmaxuh, 1, 1),
GEN_VXFORM(vmaxuw, 1, 2),
+GEN_VXFORM_207(vmaxud, 1, 3),
GEN_VXFORM(vmaxsb, 1, 4),
GEN_VXFORM(vmaxsh, 1, 5),
GEN_VXFORM(vmaxsw, 1, 6),
+GEN_VXFORM_207(vmaxsd, 1, 7),
GEN_VXFORM(vminub, 1, 8),
GEN_VXFORM(vminuh, 1, 9),
GEN_VXFORM(vminuw, 1, 10),
+GEN_VXFORM_207(vminud, 1, 11),
GEN_VXFORM(vminsb, 1, 12),
GEN_VXFORM(vminsh, 1, 13),
GEN_VXFORM(vminsw, 1, 14),
+GEN_VXFORM_207(vminsd, 1, 15),
GEN_VXFORM(vavgub, 1, 16),
GEN_VXFORM(vavguh, 1, 17),
GEN_VXFORM(vavguw, 1, 18),
@@ -9793,23 +10561,32 @@ GEN_VXFORM(vmrghw, 6, 2),
GEN_VXFORM(vmrglb, 6, 4),
GEN_VXFORM(vmrglh, 6, 5),
GEN_VXFORM(vmrglw, 6, 6),
+GEN_VXFORM_207(vmrgew, 6, 30),
+GEN_VXFORM_207(vmrgow, 6, 26),
GEN_VXFORM(vmuloub, 4, 0),
GEN_VXFORM(vmulouh, 4, 1),
+GEN_VXFORM_DUAL(vmulouw, vmuluwm, 4, 2, PPC_ALTIVEC, PPC_NONE),
GEN_VXFORM(vmulosb, 4, 4),
GEN_VXFORM(vmulosh, 4, 5),
+GEN_VXFORM_207(vmulosw, 4, 6),
GEN_VXFORM(vmuleub, 4, 8),
GEN_VXFORM(vmuleuh, 4, 9),
+GEN_VXFORM_207(vmuleuw, 4, 10),
GEN_VXFORM(vmulesb, 4, 12),
GEN_VXFORM(vmulesh, 4, 13),
+GEN_VXFORM_207(vmulesw, 4, 14),
GEN_VXFORM(vslb, 2, 4),
GEN_VXFORM(vslh, 2, 5),
GEN_VXFORM(vslw, 2, 6),
+GEN_VXFORM_207(vsld, 2, 23),
GEN_VXFORM(vsrb, 2, 8),
GEN_VXFORM(vsrh, 2, 9),
GEN_VXFORM(vsrw, 2, 10),
+GEN_VXFORM_207(vsrd, 2, 27),
GEN_VXFORM(vsrab, 2, 12),
GEN_VXFORM(vsrah, 2, 13),
GEN_VXFORM(vsraw, 2, 14),
+GEN_VXFORM_207(vsrad, 2, 15),
GEN_VXFORM(vslo, 6, 16),
GEN_VXFORM(vsro, 6, 17),
GEN_VXFORM(vaddcuw, 0, 6),
@@ -9820,25 +10597,36 @@ GEN_VXFORM(vadduws, 0, 10),
GEN_VXFORM(vaddsbs, 0, 12),
GEN_VXFORM(vaddshs, 0, 13),
GEN_VXFORM(vaddsws, 0, 14),
-GEN_VXFORM(vsububs, 0, 24),
-GEN_VXFORM(vsubuhs, 0, 25),
+GEN_VXFORM_DUAL(vsububs, bcdadd, 0, 24, PPC_ALTIVEC, PPC_NONE),
+GEN_VXFORM_DUAL(vsubuhs, bcdsub, 0, 25, PPC_ALTIVEC, PPC_NONE),
GEN_VXFORM(vsubuws, 0, 26),
GEN_VXFORM(vsubsbs, 0, 28),
GEN_VXFORM(vsubshs, 0, 29),
GEN_VXFORM(vsubsws, 0, 30),
+GEN_VXFORM_207(vadduqm, 0, 4),
+GEN_VXFORM_207(vaddcuq, 0, 5),
+GEN_VXFORM_DUAL(vaddeuqm, vaddecuq, 30, 0xFF, PPC_NONE, PPC2_ALTIVEC_207),
+GEN_VXFORM_207(vsubuqm, 0, 20),
+GEN_VXFORM_207(vsubcuq, 0, 21),
+GEN_VXFORM_DUAL(vsubeuqm, vsubecuq, 31, 0xFF, PPC_NONE, PPC2_ALTIVEC_207),
GEN_VXFORM(vrlb, 2, 0),
GEN_VXFORM(vrlh, 2, 1),
GEN_VXFORM(vrlw, 2, 2),
+GEN_VXFORM_207(vrld, 2, 3),
GEN_VXFORM(vsl, 2, 7),
GEN_VXFORM(vsr, 2, 11),
GEN_VXFORM(vpkuhum, 7, 0),
GEN_VXFORM(vpkuwum, 7, 1),
+GEN_VXFORM_207(vpkudum, 7, 17),
GEN_VXFORM(vpkuhus, 7, 2),
GEN_VXFORM(vpkuwus, 7, 3),
+GEN_VXFORM_207(vpkudus, 7, 19),
GEN_VXFORM(vpkshus, 7, 4),
GEN_VXFORM(vpkswus, 7, 5),
+GEN_VXFORM_207(vpksdus, 7, 21),
GEN_VXFORM(vpkshss, 7, 6),
GEN_VXFORM(vpkswss, 7, 7),
+GEN_VXFORM_207(vpksdss, 7, 23),
GEN_VXFORM(vpkpx, 7, 12),
GEN_VXFORM(vsum4ubs, 4, 24),
GEN_VXFORM(vsum4sbs, 4, 28),
@@ -9866,10 +10654,10 @@ GEN_VXRFORM(vcmpgtsw, 3, 14)
GEN_VXRFORM(vcmpgtub, 3, 8)
GEN_VXRFORM(vcmpgtuh, 3, 9)
GEN_VXRFORM(vcmpgtuw, 3, 10)
-GEN_VXRFORM(vcmpeqfp, 3, 3)
+GEN_VXRFORM_DUAL(vcmpeqfp, vcmpequd, 3, 3, PPC_ALTIVEC, PPC_NONE)
GEN_VXRFORM(vcmpgefp, 3, 7)
-GEN_VXRFORM(vcmpgtfp, 3, 11)
-GEN_VXRFORM(vcmpbfp, 3, 15)
+GEN_VXRFORM_DUAL(vcmpgtfp, vcmpgtud, 3, 11, PPC_ALTIVEC, PPC_NONE)
+GEN_VXRFORM_DUAL(vcmpbfp, vcmpgtsd, 3, 15, PPC_ALTIVEC, PPC_NONE)
#undef GEN_VXFORM_SIMM
#define GEN_VXFORM_SIMM(name, opc2, opc3) \
@@ -9883,8 +10671,10 @@ GEN_VXFORM_SIMM(vspltisw, 6, 14),
GEN_HANDLER(name, 0x04, opc2, opc3, 0x001f0000, PPC_ALTIVEC)
GEN_VXFORM_NOA(vupkhsb, 7, 8),
GEN_VXFORM_NOA(vupkhsh, 7, 9),
+GEN_VXFORM_207(vupkhsw, 7, 25),
GEN_VXFORM_NOA(vupklsb, 7, 10),
GEN_VXFORM_NOA(vupklsh, 7, 11),
+GEN_VXFORM_207(vupklsw, 7, 27),
GEN_VXFORM_NOA(vupkhpx, 7, 13),
GEN_VXFORM_NOA(vupklpx, 7, 15),
GEN_VXFORM_NOA(vrefp, 5, 4),
@@ -9917,15 +10707,50 @@ GEN_VAFORM_PAIRED(vmsumshm, vmsumshs, 20),
GEN_VAFORM_PAIRED(vsel, vperm, 21),
GEN_VAFORM_PAIRED(vmaddfp, vnmsubfp, 23),
+GEN_VXFORM_DUAL(vclzb, vpopcntb, 1, 28, PPC_NONE, PPC2_ALTIVEC_207),
+GEN_VXFORM_DUAL(vclzh, vpopcnth, 1, 29, PPC_NONE, PPC2_ALTIVEC_207),
+GEN_VXFORM_DUAL(vclzw, vpopcntw, 1, 30, PPC_NONE, PPC2_ALTIVEC_207),
+GEN_VXFORM_DUAL(vclzd, vpopcntd, 1, 31, PPC_NONE, PPC2_ALTIVEC_207),
+
+GEN_VXFORM_207(vbpermq, 6, 21),
+GEN_VXFORM_207(vgbbd, 6, 20),
+GEN_VXFORM_207(vpmsumb, 4, 16),
+GEN_VXFORM_207(vpmsumh, 4, 17),
+GEN_VXFORM_207(vpmsumw, 4, 18),
+GEN_VXFORM_207(vpmsumd, 4, 19),
+
+GEN_VXFORM_207(vsbox, 4, 23),
+
+GEN_VXFORM_DUAL(vcipher, vcipherlast, 4, 20, PPC_NONE, PPC2_ALTIVEC_207),
+GEN_VXFORM_DUAL(vncipher, vncipherlast, 4, 21, PPC_NONE, PPC2_ALTIVEC_207),
+
+GEN_VXFORM_207(vshasigmaw, 1, 26),
+GEN_VXFORM_207(vshasigmad, 1, 27),
+
+GEN_VXFORM_DUAL(vsldoi, vpermxor, 22, 0xFF, PPC_ALTIVEC, PPC_NONE),
+
GEN_HANDLER_E(lxsdx, 0x1F, 0x0C, 0x12, 0, PPC_NONE, PPC2_VSX),
+GEN_HANDLER_E(lxsiwax, 0x1F, 0x0C, 0x02, 0, PPC_NONE, PPC2_VSX207),
+GEN_HANDLER_E(lxsiwzx, 0x1F, 0x0C, 0x00, 0, PPC_NONE, PPC2_VSX207),
+GEN_HANDLER_E(lxsspx, 0x1F, 0x0C, 0x10, 0, PPC_NONE, PPC2_VSX207),
GEN_HANDLER_E(lxvd2x, 0x1F, 0x0C, 0x1A, 0, PPC_NONE, PPC2_VSX),
GEN_HANDLER_E(lxvdsx, 0x1F, 0x0C, 0x0A, 0, PPC_NONE, PPC2_VSX),
GEN_HANDLER_E(lxvw4x, 0x1F, 0x0C, 0x18, 0, PPC_NONE, PPC2_VSX),
GEN_HANDLER_E(stxsdx, 0x1F, 0xC, 0x16, 0, PPC_NONE, PPC2_VSX),
+GEN_HANDLER_E(stxsiwx, 0x1F, 0xC, 0x04, 0, PPC_NONE, PPC2_VSX207),
+GEN_HANDLER_E(stxsspx, 0x1F, 0xC, 0x14, 0, PPC_NONE, PPC2_VSX207),
GEN_HANDLER_E(stxvd2x, 0x1F, 0xC, 0x1E, 0, PPC_NONE, PPC2_VSX),
GEN_HANDLER_E(stxvw4x, 0x1F, 0xC, 0x1C, 0, PPC_NONE, PPC2_VSX),
+GEN_HANDLER_E(mfvsrwz, 0x1F, 0x13, 0x03, 0x0000F800, PPC_NONE, PPC2_VSX207),
+GEN_HANDLER_E(mtvsrwa, 0x1F, 0x13, 0x06, 0x0000F800, PPC_NONE, PPC2_VSX207),
+GEN_HANDLER_E(mtvsrwz, 0x1F, 0x13, 0x07, 0x0000F800, PPC_NONE, PPC2_VSX207),
+#if defined(TARGET_PPC64)
+GEN_HANDLER_E(mfvsrd, 0x1F, 0x13, 0x01, 0x0000F800, PPC_NONE, PPC2_VSX207),
+GEN_HANDLER_E(mtvsrd, 0x1F, 0x13, 0x05, 0x0000F800, PPC_NONE, PPC2_VSX207),
+#endif
+
#undef GEN_XX2FORM
#define GEN_XX2FORM(name, opc2, opc3, fl2) \
GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0, opc3, 0, PPC_NONE, fl2), \
@@ -9938,6 +10763,17 @@ GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 1, opc3, 0, PPC_NONE, fl2), \
GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 2, opc3, 0, PPC_NONE, fl2), \
GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 3, opc3, 0, PPC_NONE, fl2)
+#undef GEN_XX3_RC_FORM
+#define GEN_XX3_RC_FORM(name, opc2, opc3, fl2) \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x00, opc3 | 0x00, 0, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x01, opc3 | 0x00, 0, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x02, opc3 | 0x00, 0, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x03, opc3 | 0x00, 0, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x00, opc3 | 0x10, 0, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x01, opc3 | 0x10, 0, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x02, opc3 | 0x10, 0, PPC_NONE, fl2), \
+GEN_HANDLER2_E(name, #name, 0x3C, opc2 | 0x03, opc3 | 0x10, 0, PPC_NONE, fl2)
+
#undef GEN_XX3FORM_DM
#define GEN_XX3FORM_DM(name, opc2, opc3) \
GEN_HANDLER2_E(name, #name, 0x3C, opc2|0x00, opc3|0x00, 0, PPC_NONE, PPC2_VSX),\
@@ -9971,6 +10807,136 @@ GEN_XX2FORM(xvnabssp, 0x12, 0x1A, PPC2_VSX),
GEN_XX2FORM(xvnegsp, 0x12, 0x1B, PPC2_VSX),
GEN_XX3FORM(xvcpsgnsp, 0x00, 0x1A, PPC2_VSX),
+GEN_XX3FORM(xsadddp, 0x00, 0x04, PPC2_VSX),
+GEN_XX3FORM(xssubdp, 0x00, 0x05, PPC2_VSX),
+GEN_XX3FORM(xsmuldp, 0x00, 0x06, PPC2_VSX),
+GEN_XX3FORM(xsdivdp, 0x00, 0x07, PPC2_VSX),
+GEN_XX2FORM(xsredp, 0x14, 0x05, PPC2_VSX),
+GEN_XX2FORM(xssqrtdp, 0x16, 0x04, PPC2_VSX),
+GEN_XX2FORM(xsrsqrtedp, 0x14, 0x04, PPC2_VSX),
+GEN_XX3FORM(xstdivdp, 0x14, 0x07, PPC2_VSX),
+GEN_XX2FORM(xstsqrtdp, 0x14, 0x06, PPC2_VSX),
+GEN_XX3FORM(xsmaddadp, 0x04, 0x04, PPC2_VSX),
+GEN_XX3FORM(xsmaddmdp, 0x04, 0x05, PPC2_VSX),
+GEN_XX3FORM(xsmsubadp, 0x04, 0x06, PPC2_VSX),
+GEN_XX3FORM(xsmsubmdp, 0x04, 0x07, PPC2_VSX),
+GEN_XX3FORM(xsnmaddadp, 0x04, 0x14, PPC2_VSX),
+GEN_XX3FORM(xsnmaddmdp, 0x04, 0x15, PPC2_VSX),
+GEN_XX3FORM(xsnmsubadp, 0x04, 0x16, PPC2_VSX),
+GEN_XX3FORM(xsnmsubmdp, 0x04, 0x17, PPC2_VSX),
+GEN_XX2FORM(xscmpodp, 0x0C, 0x05, PPC2_VSX),
+GEN_XX2FORM(xscmpudp, 0x0C, 0x04, PPC2_VSX),
+GEN_XX3FORM(xsmaxdp, 0x00, 0x14, PPC2_VSX),
+GEN_XX3FORM(xsmindp, 0x00, 0x15, PPC2_VSX),
+GEN_XX2FORM(xscvdpsp, 0x12, 0x10, PPC2_VSX),
+GEN_XX2FORM(xscvdpspn, 0x16, 0x10, PPC2_VSX207),
+GEN_XX2FORM(xscvspdp, 0x12, 0x14, PPC2_VSX),
+GEN_XX2FORM(xscvspdpn, 0x16, 0x14, PPC2_VSX207),
+GEN_XX2FORM(xscvdpsxds, 0x10, 0x15, PPC2_VSX),
+GEN_XX2FORM(xscvdpsxws, 0x10, 0x05, PPC2_VSX),
+GEN_XX2FORM(xscvdpuxds, 0x10, 0x14, PPC2_VSX),
+GEN_XX2FORM(xscvdpuxws, 0x10, 0x04, PPC2_VSX),
+GEN_XX2FORM(xscvsxddp, 0x10, 0x17, PPC2_VSX),
+GEN_XX2FORM(xscvuxddp, 0x10, 0x16, PPC2_VSX),
+GEN_XX2FORM(xsrdpi, 0x12, 0x04, PPC2_VSX),
+GEN_XX2FORM(xsrdpic, 0x16, 0x06, PPC2_VSX),
+GEN_XX2FORM(xsrdpim, 0x12, 0x07, PPC2_VSX),
+GEN_XX2FORM(xsrdpip, 0x12, 0x06, PPC2_VSX),
+GEN_XX2FORM(xsrdpiz, 0x12, 0x05, PPC2_VSX),
+
+GEN_XX3FORM(xsaddsp, 0x00, 0x00, PPC2_VSX207),
+GEN_XX3FORM(xssubsp, 0x00, 0x01, PPC2_VSX207),
+GEN_XX3FORM(xsmulsp, 0x00, 0x02, PPC2_VSX207),
+GEN_XX3FORM(xsdivsp, 0x00, 0x03, PPC2_VSX207),
+GEN_XX2FORM(xsresp, 0x14, 0x01, PPC2_VSX207),
+GEN_XX2FORM(xsrsp, 0x12, 0x11, PPC2_VSX207),
+GEN_XX2FORM(xssqrtsp, 0x16, 0x00, PPC2_VSX207),
+GEN_XX2FORM(xsrsqrtesp, 0x14, 0x00, PPC2_VSX207),
+GEN_XX3FORM(xsmaddasp, 0x04, 0x00, PPC2_VSX207),
+GEN_XX3FORM(xsmaddmsp, 0x04, 0x01, PPC2_VSX207),
+GEN_XX3FORM(xsmsubasp, 0x04, 0x02, PPC2_VSX207),
+GEN_XX3FORM(xsmsubmsp, 0x04, 0x03, PPC2_VSX207),
+GEN_XX3FORM(xsnmaddasp, 0x04, 0x10, PPC2_VSX207),
+GEN_XX3FORM(xsnmaddmsp, 0x04, 0x11, PPC2_VSX207),
+GEN_XX3FORM(xsnmsubasp, 0x04, 0x12, PPC2_VSX207),
+GEN_XX3FORM(xsnmsubmsp, 0x04, 0x13, PPC2_VSX207),
+GEN_XX2FORM(xscvsxdsp, 0x10, 0x13, PPC2_VSX207),
+GEN_XX2FORM(xscvuxdsp, 0x10, 0x12, PPC2_VSX207),
+
+GEN_XX3FORM(xvadddp, 0x00, 0x0C, PPC2_VSX),
+GEN_XX3FORM(xvsubdp, 0x00, 0x0D, PPC2_VSX),
+GEN_XX3FORM(xvmuldp, 0x00, 0x0E, PPC2_VSX),
+GEN_XX3FORM(xvdivdp, 0x00, 0x0F, PPC2_VSX),
+GEN_XX2FORM(xvredp, 0x14, 0x0D, PPC2_VSX),
+GEN_XX2FORM(xvsqrtdp, 0x16, 0x0C, PPC2_VSX),
+GEN_XX2FORM(xvrsqrtedp, 0x14, 0x0C, PPC2_VSX),
+GEN_XX3FORM(xvtdivdp, 0x14, 0x0F, PPC2_VSX),
+GEN_XX2FORM(xvtsqrtdp, 0x14, 0x0E, PPC2_VSX),
+GEN_XX3FORM(xvmaddadp, 0x04, 0x0C, PPC2_VSX),
+GEN_XX3FORM(xvmaddmdp, 0x04, 0x0D, PPC2_VSX),
+GEN_XX3FORM(xvmsubadp, 0x04, 0x0E, PPC2_VSX),
+GEN_XX3FORM(xvmsubmdp, 0x04, 0x0F, PPC2_VSX),
+GEN_XX3FORM(xvnmaddadp, 0x04, 0x1C, PPC2_VSX),
+GEN_XX3FORM(xvnmaddmdp, 0x04, 0x1D, PPC2_VSX),
+GEN_XX3FORM(xvnmsubadp, 0x04, 0x1E, PPC2_VSX),
+GEN_XX3FORM(xvnmsubmdp, 0x04, 0x1F, PPC2_VSX),
+GEN_XX3FORM(xvmaxdp, 0x00, 0x1C, PPC2_VSX),
+GEN_XX3FORM(xvmindp, 0x00, 0x1D, PPC2_VSX),
+GEN_XX3_RC_FORM(xvcmpeqdp, 0x0C, 0x0C, PPC2_VSX),
+GEN_XX3_RC_FORM(xvcmpgtdp, 0x0C, 0x0D, PPC2_VSX),
+GEN_XX3_RC_FORM(xvcmpgedp, 0x0C, 0x0E, PPC2_VSX),
+GEN_XX2FORM(xvcvdpsp, 0x12, 0x18, PPC2_VSX),
+GEN_XX2FORM(xvcvdpsxds, 0x10, 0x1D, PPC2_VSX),
+GEN_XX2FORM(xvcvdpsxws, 0x10, 0x0D, PPC2_VSX),
+GEN_XX2FORM(xvcvdpuxds, 0x10, 0x1C, PPC2_VSX),
+GEN_XX2FORM(xvcvdpuxws, 0x10, 0x0C, PPC2_VSX),
+GEN_XX2FORM(xvcvsxddp, 0x10, 0x1F, PPC2_VSX),
+GEN_XX2FORM(xvcvuxddp, 0x10, 0x1E, PPC2_VSX),
+GEN_XX2FORM(xvcvsxwdp, 0x10, 0x0F, PPC2_VSX),
+GEN_XX2FORM(xvcvuxwdp, 0x10, 0x0E, PPC2_VSX),
+GEN_XX2FORM(xvrdpi, 0x12, 0x0C, PPC2_VSX),
+GEN_XX2FORM(xvrdpic, 0x16, 0x0E, PPC2_VSX),
+GEN_XX2FORM(xvrdpim, 0x12, 0x0F, PPC2_VSX),
+GEN_XX2FORM(xvrdpip, 0x12, 0x0E, PPC2_VSX),
+GEN_XX2FORM(xvrdpiz, 0x12, 0x0D, PPC2_VSX),
+
+GEN_XX3FORM(xvaddsp, 0x00, 0x08, PPC2_VSX),
+GEN_XX3FORM(xvsubsp, 0x00, 0x09, PPC2_VSX),
+GEN_XX3FORM(xvmulsp, 0x00, 0x0A, PPC2_VSX),
+GEN_XX3FORM(xvdivsp, 0x00, 0x0B, PPC2_VSX),
+GEN_XX2FORM(xvresp, 0x14, 0x09, PPC2_VSX),
+GEN_XX2FORM(xvsqrtsp, 0x16, 0x08, PPC2_VSX),
+GEN_XX2FORM(xvrsqrtesp, 0x14, 0x08, PPC2_VSX),
+GEN_XX3FORM(xvtdivsp, 0x14, 0x0B, PPC2_VSX),
+GEN_XX2FORM(xvtsqrtsp, 0x14, 0x0A, PPC2_VSX),
+GEN_XX3FORM(xvmaddasp, 0x04, 0x08, PPC2_VSX),
+GEN_XX3FORM(xvmaddmsp, 0x04, 0x09, PPC2_VSX),
+GEN_XX3FORM(xvmsubasp, 0x04, 0x0A, PPC2_VSX),
+GEN_XX3FORM(xvmsubmsp, 0x04, 0x0B, PPC2_VSX),
+GEN_XX3FORM(xvnmaddasp, 0x04, 0x18, PPC2_VSX),
+GEN_XX3FORM(xvnmaddmsp, 0x04, 0x19, PPC2_VSX),
+GEN_XX3FORM(xvnmsubasp, 0x04, 0x1A, PPC2_VSX),
+GEN_XX3FORM(xvnmsubmsp, 0x04, 0x1B, PPC2_VSX),
+GEN_XX3FORM(xvmaxsp, 0x00, 0x18, PPC2_VSX),
+GEN_XX3FORM(xvminsp, 0x00, 0x19, PPC2_VSX),
+GEN_XX3_RC_FORM(xvcmpeqsp, 0x0C, 0x08, PPC2_VSX),
+GEN_XX3_RC_FORM(xvcmpgtsp, 0x0C, 0x09, PPC2_VSX),
+GEN_XX3_RC_FORM(xvcmpgesp, 0x0C, 0x0A, PPC2_VSX),
+GEN_XX2FORM(xvcvspdp, 0x12, 0x1C, PPC2_VSX),
+GEN_XX2FORM(xvcvspsxds, 0x10, 0x19, PPC2_VSX),
+GEN_XX2FORM(xvcvspsxws, 0x10, 0x09, PPC2_VSX),
+GEN_XX2FORM(xvcvspuxds, 0x10, 0x18, PPC2_VSX),
+GEN_XX2FORM(xvcvspuxws, 0x10, 0x08, PPC2_VSX),
+GEN_XX2FORM(xvcvsxdsp, 0x10, 0x1B, PPC2_VSX),
+GEN_XX2FORM(xvcvuxdsp, 0x10, 0x1A, PPC2_VSX),
+GEN_XX2FORM(xvcvsxwsp, 0x10, 0x0B, PPC2_VSX),
+GEN_XX2FORM(xvcvuxwsp, 0x10, 0x0A, PPC2_VSX),
+GEN_XX2FORM(xvrspi, 0x12, 0x08, PPC2_VSX),
+GEN_XX2FORM(xvrspic, 0x16, 0x0A, PPC2_VSX),
+GEN_XX2FORM(xvrspim, 0x12, 0x0B, PPC2_VSX),
+GEN_XX2FORM(xvrspip, 0x12, 0x0A, PPC2_VSX),
+GEN_XX2FORM(xvrspiz, 0x12, 0x09, PPC2_VSX),
+
#undef VSX_LOGICAL
#define VSX_LOGICAL(name, opc2, opc3, fl2) \
GEN_XX3FORM(name, opc2, opc3, fl2)
@@ -9980,6 +10946,9 @@ VSX_LOGICAL(xxlandc, 0x8, 0x11, PPC2_VSX),
VSX_LOGICAL(xxlor, 0x8, 0x12, PPC2_VSX),
VSX_LOGICAL(xxlxor, 0x8, 0x13, PPC2_VSX),
VSX_LOGICAL(xxlnor, 0x8, 0x14, PPC2_VSX),
+VSX_LOGICAL(xxleqv, 0x8, 0x17, PPC2_VSX207),
+VSX_LOGICAL(xxlnand, 0x8, 0x16, PPC2_VSX207),
+VSX_LOGICAL(xxlorc, 0x8, 0x15, PPC2_VSX207),
GEN_XX3FORM(xxmrghw, 0x08, 0x02, PPC2_VSX),
GEN_XX3FORM(xxmrglw, 0x08, 0x06, PPC2_VSX),
GEN_XX2FORM(xxspltw, 0x08, 0x0A, PPC2_VSX),
@@ -10260,8 +11229,13 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
case POWERPC_MMU_SOFT_74xx:
#if defined(TARGET_PPC64)
case POWERPC_MMU_64B:
+ case POWERPC_MMU_2_06:
+ case POWERPC_MMU_2_06a:
+ case POWERPC_MMU_2_06d:
#endif
- cpu_fprintf(f, " SDR1 " TARGET_FMT_lx "\n", env->spr[SPR_SDR1]);
+ cpu_fprintf(f, " SDR1 " TARGET_FMT_lx " DAR " TARGET_FMT_lx
+ " DSISR " TARGET_FMT_lx "\n", env->spr[SPR_SDR1],
+ env->spr[SPR_DAR], env->spr[SPR_DSISR]);
break;
case POWERPC_MMU_BOOKE206:
cpu_fprintf(f, " MAS0 " TARGET_FMT_lx " MAS1 " TARGET_FMT_lx
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index 445c3606fe..3eafbb0d1a 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -628,6 +628,9 @@ static inline void _spr_register(CPUPPCState *env, int num,
spr->oea_read = oea_read;
spr->oea_write = oea_write;
#endif
+#if defined(CONFIG_KVM)
+ spr->one_reg_id = one_reg_id,
+#endif
env->spr[num] = initial_value;
}
@@ -1064,7 +1067,7 @@ static void gen_spr_amr (CPUPPCState *env)
spr_register_kvm(env, SPR_AMR, "AMR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
- KVM_REG_PPC_AMR, 0xffffffffffffffffULL);
+ KVM_REG_PPC_AMR, 0);
spr_register_kvm(env, SPR_UAMOR, "UAMOR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
@@ -2578,7 +2581,6 @@ static void gen_spr_8xx (CPUPPCState *env)
* HRMOR => SPR 313 (Power 2.04 hypv)
* HSRR0 => SPR 314 (Power 2.04 hypv)
* HSRR1 => SPR 315 (Power 2.04 hypv)
- * LPCR => SPR 316 (970)
* LPIDR => SPR 317 (970)
* EPR => SPR 702 (Power 2.04 emb)
* perf => 768-783 (Power 2.04)
@@ -4720,7 +4722,7 @@ POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data)
PPC_FLOAT_STFIWX | PPC_WAIT |
PPC_MEM_TLBSYNC | PPC_TLBIVAX | PPC_MEM_SYNC |
PPC_64B | PPC_POPCNTB | PPC_POPCNTWD;
- pcc->insns_flags2 = PPC2_BOOKE206 | PPC2_PRCNTL;
+ pcc->insns_flags2 = PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_PERM_ISA206;
pcc->msr_mask = 0x000000009402FB36ULL;
pcc->mmu_model = POWERPC_MMU_BOOKE206;
pcc->excp_model = POWERPC_EXCP_BOOKE;
@@ -6644,33 +6646,13 @@ static void init_proc_970 (CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
- spr_register(env, SPR_750FX_HID2, "HID2",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
spr_register(env, SPR_970_HID5, "HID5",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
POWERPC970_HID5_INIT);
- /* XXX : not implemented */
- spr_register(env, SPR_L2CR, "L2CR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, spr_access_nop,
- 0x00000000);
/* Memory management */
/* XXX: not correct */
gen_low_BATs(env);
- /* XXX : not implemented */
- spr_register(env, SPR_MMUCFG, "MMUCFG",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, SPR_NOACCESS,
- 0x00000000); /* TOFIX */
- /* XXX : not implemented */
- spr_register(env, SPR_MMUCSR0, "MMUCSR0",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000); /* TOFIX */
spr_register(env, SPR_HIOR, "SPR_HIOR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_hior, &spr_write_hior,
@@ -6744,44 +6726,24 @@ static void init_proc_970FX (CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
- spr_register(env, SPR_750FX_HID2, "HID2",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
spr_register(env, SPR_970_HID5, "HID5",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
POWERPC970_HID5_INIT);
- /* XXX : not implemented */
- spr_register(env, SPR_L2CR, "L2CR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, spr_access_nop,
- 0x00000000);
/* Memory management */
/* XXX: not correct */
gen_low_BATs(env);
- /* XXX : not implemented */
- spr_register(env, SPR_MMUCFG, "MMUCFG",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, SPR_NOACCESS,
- 0x00000000); /* TOFIX */
- /* XXX : not implemented */
- spr_register(env, SPR_MMUCSR0, "MMUCSR0",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000); /* TOFIX */
spr_register(env, SPR_HIOR, "SPR_HIOR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_hior, &spr_write_hior,
0x00000000);
spr_register(env, SPR_CTRL, "SPR_CTRL",
SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
+ SPR_NOACCESS, &spr_write_generic,
0x00000000);
spr_register(env, SPR_UCTRL, "SPR_UCTRL",
SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
+ &spr_read_generic, SPR_NOACCESS,
0x00000000);
spr_register(env, SPR_VRSAVE, "SPR_VRSAVE",
&spr_read_generic, &spr_write_generic,
@@ -6830,106 +6792,6 @@ POWERPC_FAMILY(970FX)(ObjectClass *oc, void *data)
POWERPC_FLAG_BUS_CLK;
}
-static int check_pow_970GX (CPUPPCState *env)
-{
- if (env->spr[SPR_HID0] & 0x00600000)
- return 1;
-
- return 0;
-}
-
-static void init_proc_970GX (CPUPPCState *env)
-{
- gen_spr_ne_601(env);
- gen_spr_7xx(env);
- /* Time base */
- gen_tbl(env);
- /* Hardware implementation registers */
- /* XXX : not implemented */
- spr_register(env, SPR_HID0, "HID0",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_clear,
- 0x60000000);
- /* XXX : not implemented */
- spr_register(env, SPR_HID1, "HID1",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_750FX_HID2, "HID2",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_970_HID5, "HID5",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- POWERPC970_HID5_INIT);
- /* XXX : not implemented */
- spr_register(env, SPR_L2CR, "L2CR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, spr_access_nop,
- 0x00000000);
- /* Memory management */
- /* XXX: not correct */
- gen_low_BATs(env);
- /* XXX : not implemented */
- spr_register(env, SPR_MMUCFG, "MMUCFG",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, SPR_NOACCESS,
- 0x00000000); /* TOFIX */
- /* XXX : not implemented */
- spr_register(env, SPR_MMUCSR0, "MMUCSR0",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000); /* TOFIX */
- spr_register(env, SPR_HIOR, "SPR_HIOR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_hior, &spr_write_hior,
- 0x00000000);
-#if !defined(CONFIG_USER_ONLY)
- env->slb_nr = 32;
-#endif
- init_excp_970(env);
- env->dcache_line_size = 128;
- env->icache_line_size = 128;
- /* Allocate hardware IRQ controller */
- ppc970_irq_init(env);
- /* Can't find information on what this should be on reset. This
- * value is the one used by 74xx processors. */
- vscr_init(env, 0x00010000);
-}
-
-POWERPC_FAMILY(970GX)(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
-
- dc->desc = "PowerPC 970 GX";
- pcc->init_proc = init_proc_970GX;
- pcc->check_pow = check_pow_970GX;
- pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
- PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
- PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
- PPC_FLOAT_STFIWX |
- PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
- PPC_MEM_SYNC | PPC_MEM_EIEIO |
- PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
- PPC_64B | PPC_ALTIVEC |
- PPC_SEGMENT_64B | PPC_SLBI;
- pcc->msr_mask = 0x800000000204FF36ULL;
- pcc->mmu_model = POWERPC_MMU_64B;
-#if defined(CONFIG_SOFTMMU)
- pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
-#endif
- pcc->excp_model = POWERPC_EXCP_970;
- pcc->bus_model = PPC_FLAGS_INPUT_970;
- pcc->bfd_mach = bfd_mach_ppc64;
- pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE |
- POWERPC_FLAG_BE | POWERPC_FLAG_PMM |
- POWERPC_FLAG_BUS_CLK;
-}
-
static int check_pow_970MP (CPUPPCState *env)
{
if (env->spr[SPR_HID0] & 0x01C00000)
@@ -6956,37 +6818,23 @@ static void init_proc_970MP (CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
- spr_register(env, SPR_750FX_HID2, "HID2",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
spr_register(env, SPR_970_HID5, "HID5",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
POWERPC970_HID5_INIT);
/* XXX : not implemented */
- spr_register(env, SPR_L2CR, "L2CR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, spr_access_nop,
- 0x00000000);
/* Memory management */
/* XXX: not correct */
gen_low_BATs(env);
- /* XXX : not implemented */
- spr_register(env, SPR_MMUCFG, "MMUCFG",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, SPR_NOACCESS,
- 0x00000000); /* TOFIX */
- /* XXX : not implemented */
- spr_register(env, SPR_MMUCSR0, "MMUCSR0",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000); /* TOFIX */
spr_register(env, SPR_HIOR, "SPR_HIOR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_hior, &spr_write_hior,
0x00000000);
+ /* Logical partitionning */
+ spr_register_kvm(env, SPR_LPCR, "LPCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ KVM_REG_PPC_LPCR, 0x00000000);
#if !defined(CONFIG_USER_ONLY)
env->slb_nr = 32;
#endif
@@ -7048,49 +6896,34 @@ static void init_proc_power5plus(CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
- spr_register(env, SPR_750FX_HID2, "HID2",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
spr_register(env, SPR_970_HID5, "HID5",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
POWERPC970_HID5_INIT);
- /* XXX : not implemented */
- spr_register(env, SPR_L2CR, "L2CR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, spr_access_nop,
- 0x00000000);
/* Memory management */
/* XXX: not correct */
gen_low_BATs(env);
- /* XXX : not implemented */
- spr_register(env, SPR_MMUCFG, "MMUCFG",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, SPR_NOACCESS,
- 0x00000000); /* TOFIX */
- /* XXX : not implemented */
- spr_register(env, SPR_MMUCSR0, "MMUCSR0",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000); /* TOFIX */
spr_register(env, SPR_HIOR, "SPR_HIOR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_hior, &spr_write_hior,
0x00000000);
spr_register(env, SPR_CTRL, "SPR_CTRL",
SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
+ SPR_NOACCESS, &spr_write_generic,
0x00000000);
spr_register(env, SPR_UCTRL, "SPR_UCTRL",
SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
+ &spr_read_generic, SPR_NOACCESS,
0x00000000);
spr_register(env, SPR_VRSAVE, "SPR_VRSAVE",
&spr_read_generic, &spr_write_generic,
&spr_read_generic, &spr_write_generic,
0x00000000);
+ /* Logical partitionning */
+ spr_register_kvm(env, SPR_LPCR, "LPCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ KVM_REG_PPC_LPCR, 0x00000000);
#if !defined(CONFIG_USER_ONLY)
env->slb_nr = 64;
#endif
@@ -7177,21 +7010,15 @@ static void init_proc_POWER7 (CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
KVM_REG_PPC_PMC6, 0x00000000);
#endif /* !CONFIG_USER_ONLY */
- /* Memory management */
- /* XXX : not implemented */
- spr_register(env, SPR_MMUCFG, "MMUCFG",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, SPR_NOACCESS,
- 0x00000000); /* TOFIX */
gen_spr_amr(env);
/* XXX : not implemented */
spr_register(env, SPR_CTRL, "SPR_CTRLT",
SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
+ SPR_NOACCESS, &spr_write_generic,
0x80800000);
spr_register(env, SPR_UCTRL, "SPR_CTRLF",
SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
+ &spr_read_generic, SPR_NOACCESS,
0x80800000);
spr_register(env, SPR_VRSAVE, "SPR_VRSAVE",
&spr_read_generic, &spr_write_generic,
@@ -7201,6 +7028,11 @@ static void init_proc_POWER7 (CPUPPCState *env)
&spr_read_generic, &spr_write_generic,
&spr_read_generic, &spr_write_generic,
0x00000000);
+ /* Logical partitionning */
+ spr_register_kvm(env, SPR_LPCR, "LPCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ KVM_REG_PPC_LPCR, 0x00000000);
#if !defined(CONFIG_USER_ONLY)
env->slb_nr = 32;
#endif
@@ -7229,14 +7061,19 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
+ PPC_FLOAT_FRSQRTES |
PPC_FLOAT_STFIWX |
+ PPC_FLOAT_EXT |
PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
PPC_MEM_SYNC | PPC_MEM_EIEIO |
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
PPC_64B | PPC_ALTIVEC |
PPC_SEGMENT_64B | PPC_SLBI |
PPC_POPCNTB | PPC_POPCNTWD;
- pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX | PPC2_ISA205;
+ pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX | PPC2_ISA205 |
+ PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 |
+ PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 |
+ PPC2_FP_TST_ISA206;
pcc->msr_mask = 0x800000000284FF37ULL;
pcc->mmu_model = POWERPC_MMU_2_06;
#if defined(CONFIG_SOFTMMU)
@@ -7267,14 +7104,19 @@ POWERPC_FAMILY(POWER7P)(ObjectClass *oc, void *data)
pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
+ PPC_FLOAT_FRSQRTES |
PPC_FLOAT_STFIWX |
+ PPC_FLOAT_EXT |
PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
PPC_MEM_SYNC | PPC_MEM_EIEIO |
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
PPC_64B | PPC_ALTIVEC |
PPC_SEGMENT_64B | PPC_SLBI |
PPC_POPCNTB | PPC_POPCNTWD;
- pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX | PPC2_ISA205;
+ pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX | PPC2_ISA205 |
+ PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 |
+ PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 |
+ PPC2_FP_TST_ISA206;
pcc->msr_mask = 0x800000000204FF37ULL;
pcc->mmu_model = POWERPC_MMU_2_06;
#if defined(CONFIG_SOFTMMU)
@@ -7291,6 +7133,18 @@ POWERPC_FAMILY(POWER7P)(ObjectClass *oc, void *data)
pcc->l1_icache_size = 0x8000;
}
+static void init_proc_POWER8(CPUPPCState *env)
+{
+ /* inherit P7 */
+ init_proc_POWER7(env);
+
+ /* P8 supports the TAR */
+ spr_register(env, SPR_TAR, "TAR",
+ &spr_read_generic, &spr_write_generic,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+}
+
POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -7300,19 +7154,25 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
dc->desc = "POWER8";
pcc->pvr = CPU_POWERPC_POWER8_BASE;
pcc->pvr_mask = CPU_POWERPC_POWER8_MASK;
- pcc->init_proc = init_proc_POWER7;
+ pcc->init_proc = init_proc_POWER8;
pcc->check_pow = check_pow_nocheck;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
+ PPC_FLOAT_FRSQRTES |
PPC_FLOAT_STFIWX |
+ PPC_FLOAT_EXT |
PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
PPC_MEM_SYNC | PPC_MEM_EIEIO |
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
- PPC_64B | PPC_ALTIVEC |
+ PPC_64B | PPC_64BX | PPC_ALTIVEC |
PPC_SEGMENT_64B | PPC_SLBI |
PPC_POPCNTB | PPC_POPCNTWD;
- pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX;
+ pcc->insns_flags2 = PPC2_VSX | PPC2_VSX207 | PPC2_DFP | PPC2_DBRX |
+ PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 |
+ PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 |
+ PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 |
+ PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207;
pcc->msr_mask = 0x800000000284FF36ULL;
pcc->mmu_model = POWERPC_MMU_2_06;
#if defined(CONFIG_SOFTMMU)
@@ -7987,14 +7847,12 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp)
max_smt, kvm_enabled() ? "KVM" : "TCG");
return;
}
+
+ cpu->cpu_dt_id = (cs->cpu_index / smp_threads) * max_smt
+ + (cs->cpu_index % smp_threads);
#endif
- if (kvm_enabled()) {
- if (kvmppc_fixup_cpu(cpu) != 0) {
- error_setg(errp, "Unable to virtualize selected CPU with KVM");
- return;
- }
- } else if (tcg_enabled()) {
+ if (tcg_enabled()) {
if (ppc_fixup_cpu(cpu) != 0) {
error_setg(errp, "Unable to emulate selected CPU with TCG");
return;
@@ -8149,9 +8007,10 @@ static void ppc_cpu_realizefn(DeviceState *dev, Error **errp)
}
printf("PowerPC %-12s : PVR %08x MSR %016" PRIx64 "\n"
" MMU model : %s\n",
- pcc->name, pcc->pvr, pcc->msr_mask, mmu_model);
+ object_class_get_name(OBJECT_CLASS(pcc)),
+ pcc->pvr, pcc->msr_mask, mmu_model);
#if !defined(CONFIG_USER_ONLY)
- if (env->tlb != NULL) {
+ if (env->tlb.tlb6) {
printf(" %d %s TLB in %d ways\n",
env->nb_tlb, env->id_tlbs ? "splitted" : "merged",
env->nb_ways);
@@ -8598,6 +8457,7 @@ static void ppc_cpu_initfn(Object *obj)
cs->env_ptr = env;
cpu_exec_init(env);
+ cpu->cpu_dt_id = cs->cpu_index;
env->msr_mask = pcc->msr_mask;
env->mmu_model = pcc->mmu_model;
diff --git a/target-s390x/ioinst.h b/target-s390x/ioinst.h
index 613da49b3b..5bbc67d15e 100644
--- a/target-s390x/ioinst.h
+++ b/target-s390x/ioinst.h
@@ -212,6 +212,8 @@ typedef struct IOIntCode {
#define IO_INT_WORD_ISC(_int_word) ((_int_word & 0x38000000) >> 24)
#define ISC_TO_ISC_BITS(_isc) ((0x80 >> _isc) << 24)
+#define IO_INT_WORD_AI 0x80000000
+
int ioinst_disassemble_sch_ident(uint32_t value, int *m, int *cssid, int *ssid,
int *schid);
void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1);
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 11feda9eb9..56b9af7505 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -891,8 +891,12 @@ void kvm_s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id,
{
uint32_t type;
- type = ((subchannel_id & 0xff00) << 24) |
- ((subchannel_id & 0x00060) << 22) | (subchannel_nr << 16);
+ if (io_int_word & IO_INT_WORD_AI) {
+ type = KVM_S390_INT_IO(1, 0, 0, 0);
+ } else {
+ type = ((subchannel_id & 0xff00) << 24) |
+ ((subchannel_id & 0x00060) << 22) | (subchannel_nr << 16);
+ }
kvm_s390_interrupt_internal(cpu, type,
((uint32_t)subchannel_id << 16) | subchannel_nr,
((uint64_t)io_int_parm << 32) | io_int_word, 1);
diff --git a/trace-events b/trace-events
index d86f98cb31..aec420292c 100644
--- a/trace-events
+++ b/trace-events
@@ -1020,6 +1020,15 @@ gd_switch(int width, int height) "width=%d, height=%d"
gd_update(int x, int y, int w, int h) "x=%d, y=%d, w=%d, h=%d"
gd_key_event(int gdk_keycode, int qemu_keycode, const char *action) "translated GDK keycode %d to QEMU keycode %d (%s)"
+# ui/input.c
+input_event_key_number(int conidx, int number, bool down) "con %d, key number 0x%d, down %d"
+input_event_key_qcode(int conidx, const char *qcode, bool down) "con %d, key qcode %s, down %d"
+input_event_btn(int conidx, const char *btn, bool down) "con %d, button %s, down %d"
+input_event_rel(int conidx, const char *axis, int value) "con %d, axis %s, value %d"
+input_event_abs(int conidx, const char *axis, int value) "con %d, axis %s, value 0x%x"
+input_event_sync(void) ""
+input_mouse_mode(int absolute) "absolute %d"
+
# hw/display/vmware_vga.c
vmware_value_read(uint32_t index, uint32_t value) "index %d, value 0x%x"
vmware_value_write(uint32_t index, uint32_t value) "index %d, value 0x%x"
@@ -1136,6 +1145,7 @@ xics_ics_eoi(int nr) "ics_eoi: irq %#x"
# hw/ppc/spapr_iommu.c
spapr_iommu_put(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t ret) "liobn=%"PRIx64" ioba=0x%"PRIx64" tce=0x%"PRIx64" ret=%"PRId64
+spapr_iommu_get(uint64_t liobn, uint64_t ioba, uint64_t ret, uint64_t tce) "liobn=%"PRIx64" ioba=0x%"PRIx64" ret=%"PRId64" tce=0x%"PRIx64
spapr_iommu_xlate(uint64_t liobn, uint64_t ioba, uint64_t tce, unsigned perm, unsigned pgsize) "liobn=%"PRIx64" 0x%"PRIx64" -> 0x%"PRIx64" perm=%u mask=%x"
spapr_iommu_new_table(uint64_t liobn, void *tcet, void *table, int fd) "liobn=%"PRIx64" tcet=%p table=%p fd=%d"
@@ -1157,6 +1167,7 @@ css_chpid_add(uint8_t cssid, uint8_t chpid, uint8_t type) "CSS: add chpid %x.%02
css_new_image(uint8_t cssid, const char *default_cssid) "CSS: add css image %02x %s"
css_assign_subch(const char *do_assign, uint8_t cssid, uint8_t ssid, uint16_t schid, uint16_t devno) "CSS: %s %x.%x.%04x (devno %04x)"
css_io_interrupt(int cssid, int ssid, int schid, uint32_t intparm, uint8_t isc, const char *conditional) "CSS: I/O interrupt on sch %x.%x.%04x (intparm %08x, isc %x) %s"
+css_adapter_interrupt(uint8_t isc) "CSS: adapter I/O interrupt (isc %x)"
# hw/s390x/virtio-ccw.c
virtio_ccw_interpret_ccw(int cssid, int ssid, int schid, int cmd_code) "VIRTIO-CCW: %x.%x.%04x: interpret command %x"
@@ -1176,6 +1187,8 @@ kvm_vm_ioctl(int type, void *arg) "type 0x%x, arg %p"
kvm_vcpu_ioctl(int cpu_index, int type, void *arg) "cpu_index %d, type 0x%x, arg %p"
kvm_run_exit(int cpu_index, uint32_t reason) "cpu_index %d, reason %d"
kvm_device_ioctl(int fd, int type, void *arg) "dev fd %d, type 0x%x, arg %p"
+kvm_failed_spr_set(int str, const char *msg) "Warning: Unable to set SPR %d to KVM: %s"
+kvm_failed_spr_get(int str, const char *msg) "Warning: Unable to retrieve SPR %d from KVM: %s"
# memory.c
memory_region_ops_read(void *mr, uint64_t addr, uint64_t value, unsigned size) "mr %p addr %#"PRIx64" value %#"PRIx64" size %u"
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index f33be47576..6f2294efda 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -7,14 +7,14 @@ vnc-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
vnc-obj-$(CONFIG_VNC_WS) += vnc-ws.o
vnc-obj-y += vnc-jobs.o
-common-obj-y += keymaps.o console.o cursor.o input.o qemu-pixman.o
+common-obj-y += keymaps.o console.o cursor.o input.o input-legacy.o qemu-pixman.o
common-obj-$(CONFIG_SPICE) += spice-core.o spice-input.o spice-display.o
-common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
+common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o sdl2.o
common-obj-$(CONFIG_COCOA) += cocoa.o
common-obj-$(CONFIG_CURSES) += curses.o
common-obj-$(CONFIG_VNC) += $(vnc-obj-y)
common-obj-$(CONFIG_GTK) += gtk.o x_keymap.o
-$(obj)/sdl.o $(obj)/sdl_zoom.o: QEMU_CFLAGS += $(SDL_CFLAGS)
+$(obj)/sdl.o $(obj)/sdl_zoom.o $(obj)/sdl2.o: QEMU_CFLAGS += $(SDL_CFLAGS)
$(obj)/gtk.o: QEMU_CFLAGS += $(GTK_CFLAGS) $(VTE_CFLAGS)
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 866177770a..f20fd1ffa2 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -27,6 +27,7 @@
#include "qemu-common.h"
#include "ui/console.h"
+#include "ui/input.h"
#include "sysemu/sysemu.h"
#ifndef MAC_OS_X_VERSION_10_4
@@ -49,14 +50,6 @@
#endif
#define cgrect(nsrect) (*(CGRect *)&(nsrect))
-#define COCOA_MOUSE_EVENT \
- if (isTabletEnabled) { \
- kbd_mouse_event((int)(p.x * 0x7FFF / (screen.width - 1)), (int)((screen.height - p.y) * 0x7FFF / (screen.height - 1)), 0, buttons); \
- } else if (isMouseGrabbed) { \
- kbd_mouse_event((int)[event deltaX], (int)[event deltaY], 0, buttons); \
- } else { \
- [NSApp sendEvent:event]; \
- }
typedef struct {
int width;
@@ -67,6 +60,7 @@ typedef struct {
NSWindow *normalWindow;
static DisplayChangeListener *dcl;
+static int last_buttons;
int gArgc;
char **gArgv;
@@ -501,6 +495,7 @@ QemuCocoaView *cocoaView;
int buttons = 0;
int keycode;
+ bool mouse_event = false;
NSPoint p = [event locationInWindow];
switch ([event type]) {
@@ -514,16 +509,14 @@ QemuCocoaView *cocoaView;
if (keycode) {
if (keycode == 58 || keycode == 69) { // emulate caps lock and num lock keydown and keyup
- kbd_put_keycode(keycode);
- kbd_put_keycode(keycode | 0x80);
+ qemu_input_event_send_key_number(dcl->con, keycode, true);
+ qemu_input_event_send_key_number(dcl->con, keycode, false);
} else if (qemu_console_is_graphic(NULL)) {
- if (keycode & 0x80)
- kbd_put_keycode(0xe0);
if (modifiers_state[keycode] == 0) { // keydown
- kbd_put_keycode(keycode & 0x7f);
+ qemu_input_event_send_key_number(dcl->con, keycode, true);
modifiers_state[keycode] = 1;
} else { // keyup
- kbd_put_keycode(keycode | 0x80);
+ qemu_input_event_send_key_number(dcl->con, keycode, false);
modifiers_state[keycode] = 0;
}
}
@@ -557,9 +550,7 @@ QemuCocoaView *cocoaView;
// handle keys for graphic console
} else if (qemu_console_is_graphic(NULL)) {
- if (keycode & 0x80) //check bit for e0 in front
- kbd_put_keycode(0xe0);
- kbd_put_keycode(keycode & 0x7f); //remove e0 bit in front
+ qemu_input_event_send_key_number(dcl->con, keycode, true);
// handlekeys for Monitor
} else {
@@ -607,9 +598,7 @@ QemuCocoaView *cocoaView;
}
if (qemu_console_is_graphic(NULL)) {
- if (keycode & 0x80)
- kbd_put_keycode(0xe0);
- kbd_put_keycode(keycode | 0x80); //add 128 to signal release of key
+ qemu_input_event_send_key_number(dcl->con, keycode, false);
}
break;
case NSMouseMoved:
@@ -626,7 +615,7 @@ QemuCocoaView *cocoaView;
}
}
}
- COCOA_MOUSE_EVENT
+ mouse_event = true;
break;
case NSLeftMouseDown:
if ([event modifierFlags] & NSCommandKeyMask) {
@@ -634,15 +623,15 @@ QemuCocoaView *cocoaView;
} else {
buttons |= MOUSE_EVENT_LBUTTON;
}
- COCOA_MOUSE_EVENT
+ mouse_event = true;
break;
case NSRightMouseDown:
buttons |= MOUSE_EVENT_RBUTTON;
- COCOA_MOUSE_EVENT
+ mouse_event = true;
break;
case NSOtherMouseDown:
buttons |= MOUSE_EVENT_MBUTTON;
- COCOA_MOUSE_EVENT
+ mouse_event = true;
break;
case NSLeftMouseDragged:
if ([event modifierFlags] & NSCommandKeyMask) {
@@ -650,19 +639,19 @@ QemuCocoaView *cocoaView;
} else {
buttons |= MOUSE_EVENT_LBUTTON;
}
- COCOA_MOUSE_EVENT
+ mouse_event = true;
break;
case NSRightMouseDragged:
buttons |= MOUSE_EVENT_RBUTTON;
- COCOA_MOUSE_EVENT
+ mouse_event = true;
break;
case NSOtherMouseDragged:
buttons |= MOUSE_EVENT_MBUTTON;
- COCOA_MOUSE_EVENT
+ mouse_event = true;
break;
case NSLeftMouseUp:
if (isTabletEnabled) {
- COCOA_MOUSE_EVENT
+ mouse_event = true;
} else if (!isMouseGrabbed) {
if (p.x > -1 && p.x < screen.width && p.y > -1 && p.y < screen.height) {
[self grabMouse];
@@ -670,18 +659,20 @@ QemuCocoaView *cocoaView;
[NSApp sendEvent:event];
}
} else {
- COCOA_MOUSE_EVENT
+ mouse_event = true;
}
break;
case NSRightMouseUp:
- COCOA_MOUSE_EVENT
+ mouse_event = true;
break;
case NSOtherMouseUp:
- COCOA_MOUSE_EVENT
+ mouse_event = true;
break;
case NSScrollWheel:
if (isTabletEnabled || isMouseGrabbed) {
- kbd_mouse_event(0, 0, -[event deltaY], 0);
+ buttons |= ([event deltaY] < 0) ?
+ MOUSE_EVENT_WHEELUP : MOUSE_EVENT_WHEELDN;
+ mouse_event = true;
} else {
[NSApp sendEvent:event];
}
@@ -689,6 +680,30 @@ QemuCocoaView *cocoaView;
default:
[NSApp sendEvent:event];
}
+
+ if (mouse_event) {
+ if (last_buttons != buttons) {
+ static uint32_t bmap[INPUT_BUTTON_MAX] = {
+ [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
+ [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
+ [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
+ [INPUT_BUTTON_WHEEL_UP] = MOUSE_EVENT_WHEELUP,
+ [INPUT_BUTTON_WHEEL_DOWN] = MOUSE_EVENT_WHEELDN,
+ };
+ qemu_input_update_buttons(dcl->con, bmap, last_buttons, buttons);
+ last_buttons = buttons;
+ }
+ if (isTabletEnabled) {
+ qemu_input_queue_abs(dcl->con, INPUT_AXIS_X, p.x, screen.width);
+ qemu_input_queue_abs(dcl->con, INPUT_AXIS_Y, p.y, screen.height);
+ } else if (isMouseGrabbed) {
+ qemu_input_queue_rel(dcl->con, INPUT_AXIS_X, (int)[event deltaX]);
+ qemu_input_queue_rel(dcl->con, INPUT_AXIS_Y, (int)[event deltaY]);
+ } else {
+ [NSApp sendEvent:event];
+ }
+ qemu_input_event_sync();
+ }
}
- (void) grabMouse
@@ -1023,7 +1038,7 @@ static void cocoa_refresh(DisplayChangeListener *dcl)
COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n");
- if (kbd_mouse_is_absolute()) {
+ if (qemu_input_is_absolute()) {
if (![cocoaView isAbsoluteEnabled]) {
if ([cocoaView isMouseGrabbed]) {
[cocoaView ungrabMouse];
diff --git a/ui/console.c b/ui/console.c
index 502e1600ab..4df251d579 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -124,6 +124,8 @@ struct QemuConsole {
/* Graphic console state. */
Object *device;
+ uint32_t head;
+ QemuUIInfo ui_info;
const GraphicHwOps *hw_ops;
void *hw;
@@ -1179,6 +1181,8 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type)
s = QEMU_CONSOLE(obj);
object_property_add_link(obj, "device", TYPE_DEVICE,
(Object **)&s->device, &local_err);
+ object_property_add_uint32_ptr(obj, "head",
+ &s->head, &local_err);
if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
(console_type == GRAPHIC_CONSOLE))) {
@@ -1344,6 +1348,16 @@ void unregister_displaychangelistener(DisplayChangeListener *dcl)
gui_setup_refresh(ds);
}
+int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info)
+{
+ assert(con != NULL);
+ con->ui_info = *info;
+ if (con->hw_ops->ui_info) {
+ return con->hw_ops->ui_info(con->hw, con->head, info);
+ }
+ return -1;
+}
+
void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
{
DisplayState *s = con->ds;
@@ -1569,7 +1583,7 @@ DisplayState *init_displaystate(void)
return display_state;
}
-QemuConsole *graphic_console_init(DeviceState *dev,
+QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
const GraphicHwOps *hw_ops,
void *opaque)
{
@@ -1587,6 +1601,8 @@ QemuConsole *graphic_console_init(DeviceState *dev,
if (dev) {
object_property_set_link(OBJECT(s), OBJECT(dev),
"device", &local_err);
+ object_property_set_int(OBJECT(s), head,
+ "head", &local_err);
}
s->surface = qemu_create_displaysurface(width, height);
@@ -1601,10 +1617,11 @@ QemuConsole *qemu_console_lookup_by_index(unsigned int index)
return consoles[index];
}
-QemuConsole *qemu_console_lookup_by_device(DeviceState *dev)
+QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
{
Error *local_err = NULL;
Object *obj;
+ uint32_t h;
int i;
for (i = 0; i < nb_consoles; i++) {
@@ -1613,9 +1630,15 @@ QemuConsole *qemu_console_lookup_by_device(DeviceState *dev)
}
obj = object_property_get_link(OBJECT(consoles[i]),
"device", &local_err);
- if (DEVICE(obj) == dev) {
- return consoles[i];
+ if (DEVICE(obj) != dev) {
+ continue;
}
+ h = object_property_get_int(OBJECT(consoles[i]),
+ "head", &local_err);
+ if (h != head) {
+ continue;
+ }
+ return consoles[i];
}
return NULL;
}
@@ -1641,6 +1664,44 @@ bool qemu_console_is_fixedsize(QemuConsole *con)
return con && (con->console_type != TEXT_CONSOLE);
}
+int qemu_console_get_index(QemuConsole *con)
+{
+ if (con == NULL) {
+ con = active_console;
+ }
+ return con ? con->index : -1;
+}
+
+uint32_t qemu_console_get_head(QemuConsole *con)
+{
+ if (con == NULL) {
+ con = active_console;
+ }
+ return con ? con->head : -1;
+}
+
+QemuUIInfo *qemu_console_get_ui_info(QemuConsole *con)
+{
+ assert(con != NULL);
+ return &con->ui_info;
+}
+
+int qemu_console_get_width(QemuConsole *con, int fallback)
+{
+ if (con == NULL) {
+ con = active_console;
+ }
+ return con ? surface_width(con->surface) : fallback;
+}
+
+int qemu_console_get_height(QemuConsole *con, int fallback)
+{
+ if (con == NULL) {
+ con = active_console;
+ }
+ return con ? surface_height(con->surface) : fallback;
+}
+
static void text_console_set_echo(CharDriverState *chr, bool echo)
{
QemuConsole *s = chr->opaque;
diff --git a/ui/curses.c b/ui/curses.c
index dbc3d5ec73..b044790e43 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -30,6 +30,7 @@
#include "qemu-common.h"
#include "ui/console.h"
+#include "ui/input.h"
#include "sysemu/sysemu.h"
#define FONT_HEIGHT 16
@@ -274,32 +275,34 @@ static void curses_refresh(DisplayChangeListener *dcl)
if (qemu_console_is_graphic(NULL)) {
/* since terminals don't know about key press and release
* events, we need to emit both for each key received */
- if (keycode & SHIFT)
- kbd_put_keycode(SHIFT_CODE);
- if (keycode & CNTRL)
- kbd_put_keycode(CNTRL_CODE);
- if (keycode & ALT)
- kbd_put_keycode(ALT_CODE);
+ if (keycode & SHIFT) {
+ qemu_input_event_send_key_number(NULL, SHIFT_CODE, true);
+ }
+ if (keycode & CNTRL) {
+ qemu_input_event_send_key_number(NULL, CNTRL_CODE, true);
+ }
+ if (keycode & ALT) {
+ qemu_input_event_send_key_number(NULL, ALT_CODE, true);
+ }
if (keycode & ALTGR) {
- kbd_put_keycode(SCANCODE_EMUL0);
- kbd_put_keycode(ALT_CODE);
+ qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, true);
}
- if (keycode & GREY)
- kbd_put_keycode(GREY_CODE);
- kbd_put_keycode(keycode & KEY_MASK);
- if (keycode & GREY)
- kbd_put_keycode(GREY_CODE);
- kbd_put_keycode((keycode & KEY_MASK) | KEY_RELEASE);
+
+ qemu_input_event_send_key_number(NULL, keycode, true);
+ qemu_input_event_send_key_number(NULL, keycode, false);
+
if (keycode & ALTGR) {
- kbd_put_keycode(SCANCODE_EMUL0);
- kbd_put_keycode(ALT_CODE | KEY_RELEASE);
+ qemu_input_event_send_key_number(NULL, GREY | ALT_CODE, false);
+ }
+ if (keycode & ALT) {
+ qemu_input_event_send_key_number(NULL, ALT_CODE, false);
+ }
+ if (keycode & CNTRL) {
+ qemu_input_event_send_key_number(NULL, CNTRL_CODE, false);
+ }
+ if (keycode & SHIFT) {
+ qemu_input_event_send_key_number(NULL, SHIFT_CODE, false);
}
- if (keycode & ALT)
- kbd_put_keycode(ALT_CODE | KEY_RELEASE);
- if (keycode & CNTRL)
- kbd_put_keycode(CNTRL_CODE | KEY_RELEASE);
- if (keycode & SHIFT)
- kbd_put_keycode(SHIFT_CODE | KEY_RELEASE);
} else {
keysym = curses2qemu[chr];
if (keysym == -1)
diff --git a/ui/gtk.c b/ui/gtk.c
index a633d89346..185149571e 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -59,6 +59,7 @@
#include "trace.h"
#include "ui/console.h"
+#include "ui/input.h"
#include "sysemu/sysemu.h"
#include "qmp-commands.h"
#include "x_keymap.h"
@@ -193,7 +194,7 @@ static void gd_update_cursor(GtkDisplayState *s, gboolean override)
on_vga = gd_on_vga(s);
if ((override || on_vga) &&
- (s->full_screen || kbd_mouse_is_absolute() || gd_is_grab_active(s))) {
+ (s->full_screen || qemu_input_is_absolute() || gd_is_grab_active(s))) {
gdk_window_set_cursor(window, s->null_cursor);
} else {
gdk_window_set_cursor(window, NULL);
@@ -280,10 +281,7 @@ static void gtk_release_modifiers(GtkDisplayState *s)
if (!s->modifier_pressed[i]) {
continue;
}
- if (keycode & SCANCODE_GREY) {
- kbd_put_keycode(SCANCODE_EMUL0);
- }
- kbd_put_keycode(keycode | SCANCODE_UP);
+ qemu_input_event_send_key_number(s->dcl.con, keycode, false);
s->modifier_pressed[i] = false;
}
}
@@ -582,7 +580,6 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
void *opaque)
{
GtkDisplayState *s = opaque;
- int dx, dy;
int x, y;
int mx, my;
int fbh, fbw;
@@ -610,25 +607,21 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
return TRUE;
}
- if (kbd_mouse_is_absolute()) {
- dx = x * 0x7FFF / (surface_width(s->ds) - 1);
- dy = y * 0x7FFF / (surface_height(s->ds) - 1);
- } else if (s->last_x == -1 || s->last_y == -1) {
- dx = 0;
- dy = 0;
- } else {
- dx = x - s->last_x;
- dy = y - s->last_y;
+ if (qemu_input_is_absolute()) {
+ qemu_input_queue_abs(s->dcl.con, INPUT_AXIS_X, x,
+ surface_width(s->ds));
+ qemu_input_queue_abs(s->dcl.con, INPUT_AXIS_Y, y,
+ surface_height(s->ds));
+ qemu_input_event_sync();
+ } else if (s->last_x != -1 && s->last_y != -1 && gd_is_grab_active(s)) {
+ qemu_input_queue_rel(s->dcl.con, INPUT_AXIS_X, x - s->last_x);
+ qemu_input_queue_rel(s->dcl.con, INPUT_AXIS_Y, y - s->last_y);
+ qemu_input_event_sync();
}
-
s->last_x = x;
s->last_y = y;
- if (kbd_mouse_is_absolute() || gd_is_grab_active(s)) {
- kbd_mouse_event(dx, dy, 0, s->button_mask);
- }
-
- if (!kbd_mouse_is_absolute() && gd_is_grab_active(s)) {
+ if (!qemu_input_is_absolute() && gd_is_grab_active(s)) {
GdkScreen *screen = gtk_widget_get_screen(s->drawing_area);
int x = (int)motion->x_root;
int y = (int)motion->y_root;
@@ -673,35 +666,20 @@ static gboolean gd_button_event(GtkWidget *widget, GdkEventButton *button,
void *opaque)
{
GtkDisplayState *s = opaque;
- int dx, dy;
- int n;
+ InputButton btn;
if (button->button == 1) {
- n = 0x01;
+ btn = INPUT_BUTTON_LEFT;
} else if (button->button == 2) {
- n = 0x04;
+ btn = INPUT_BUTTON_MIDDLE;
} else if (button->button == 3) {
- n = 0x02;
+ btn = INPUT_BUTTON_RIGHT;
} else {
- n = 0x00;
- }
-
- if (button->type == GDK_BUTTON_PRESS) {
- s->button_mask |= n;
- } else if (button->type == GDK_BUTTON_RELEASE) {
- s->button_mask &= ~n;
- }
-
- if (kbd_mouse_is_absolute()) {
- dx = s->last_x * 0x7FFF / (surface_width(s->ds) - 1);
- dy = s->last_y * 0x7FFF / (surface_height(s->ds) - 1);
- } else {
- dx = 0;
- dy = 0;
+ return TRUE;
}
- kbd_mouse_event(dx, dy, 0, s->button_mask);
-
+ qemu_input_queue_btn(s->dcl.con, btn, button->type == GDK_BUTTON_PRESS);
+ qemu_input_event_sync();
return TRUE;
}
@@ -745,17 +723,8 @@ static gboolean gd_key_event(GtkWidget *widget, GdkEventKey *key, void *opaque)
}
}
- if (qemu_keycode & SCANCODE_GREY) {
- kbd_put_keycode(SCANCODE_EMUL0);
- }
-
- if (key->type == GDK_KEY_PRESS) {
- kbd_put_keycode(qemu_keycode & SCANCODE_KEYCODEMASK);
- } else if (key->type == GDK_KEY_RELEASE) {
- kbd_put_keycode(qemu_keycode | SCANCODE_UP);
- } else {
- g_assert_not_reached();
- }
+ qemu_input_event_send_key_number(s->dcl.con, qemu_keycode,
+ key->type == GDK_KEY_PRESS);
return TRUE;
}
diff --git a/ui/input-legacy.c b/ui/input-legacy.c
new file mode 100644
index 0000000000..f38984b192
--- /dev/null
+++ b/ui/input-legacy.c
@@ -0,0 +1,453 @@
+/*
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * 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.
+ */
+
+#include "sysemu/sysemu.h"
+#include "monitor/monitor.h"
+#include "ui/console.h"
+#include "qapi/error.h"
+#include "qmp-commands.h"
+#include "qapi-types.h"
+#include "ui/keymaps.h"
+#include "ui/input.h"
+
+struct QEMUPutMouseEntry {
+ QEMUPutMouseEvent *qemu_put_mouse_event;
+ void *qemu_put_mouse_event_opaque;
+ int qemu_put_mouse_event_absolute;
+
+ /* new input core */
+ QemuInputHandler h;
+ QemuInputHandlerState *s;
+ int axis[INPUT_AXIS_MAX];
+ int buttons;
+};
+
+struct QEMUPutKbdEntry {
+ QEMUPutKBDEvent *put_kbd;
+ void *opaque;
+ QemuInputHandlerState *s;
+};
+
+struct QEMUPutLEDEntry {
+ QEMUPutLEDEvent *put_led;
+ void *opaque;
+ QTAILQ_ENTRY(QEMUPutLEDEntry) next;
+};
+
+static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers =
+ QTAILQ_HEAD_INITIALIZER(led_handlers);
+static QTAILQ_HEAD(, QEMUPutMouseEntry) mouse_handlers =
+ QTAILQ_HEAD_INITIALIZER(mouse_handlers);
+
+static const int key_defs[] = {
+ [Q_KEY_CODE_SHIFT] = 0x2a,
+ [Q_KEY_CODE_SHIFT_R] = 0x36,
+
+ [Q_KEY_CODE_ALT] = 0x38,
+ [Q_KEY_CODE_ALT_R] = 0xb8,
+ [Q_KEY_CODE_ALTGR] = 0x64,
+ [Q_KEY_CODE_ALTGR_R] = 0xe4,
+ [Q_KEY_CODE_CTRL] = 0x1d,
+ [Q_KEY_CODE_CTRL_R] = 0x9d,
+
+ [Q_KEY_CODE_MENU] = 0xdd,
+
+ [Q_KEY_CODE_ESC] = 0x01,
+
+ [Q_KEY_CODE_1] = 0x02,
+ [Q_KEY_CODE_2] = 0x03,
+ [Q_KEY_CODE_3] = 0x04,
+ [Q_KEY_CODE_4] = 0x05,
+ [Q_KEY_CODE_5] = 0x06,
+ [Q_KEY_CODE_6] = 0x07,
+ [Q_KEY_CODE_7] = 0x08,
+ [Q_KEY_CODE_8] = 0x09,
+ [Q_KEY_CODE_9] = 0x0a,
+ [Q_KEY_CODE_0] = 0x0b,
+ [Q_KEY_CODE_MINUS] = 0x0c,
+ [Q_KEY_CODE_EQUAL] = 0x0d,
+ [Q_KEY_CODE_BACKSPACE] = 0x0e,
+
+ [Q_KEY_CODE_TAB] = 0x0f,
+ [Q_KEY_CODE_Q] = 0x10,
+ [Q_KEY_CODE_W] = 0x11,
+ [Q_KEY_CODE_E] = 0x12,
+ [Q_KEY_CODE_R] = 0x13,
+ [Q_KEY_CODE_T] = 0x14,
+ [Q_KEY_CODE_Y] = 0x15,
+ [Q_KEY_CODE_U] = 0x16,
+ [Q_KEY_CODE_I] = 0x17,
+ [Q_KEY_CODE_O] = 0x18,
+ [Q_KEY_CODE_P] = 0x19,
+ [Q_KEY_CODE_BRACKET_LEFT] = 0x1a,
+ [Q_KEY_CODE_BRACKET_RIGHT] = 0x1b,
+ [Q_KEY_CODE_RET] = 0x1c,
+
+ [Q_KEY_CODE_A] = 0x1e,
+ [Q_KEY_CODE_S] = 0x1f,
+ [Q_KEY_CODE_D] = 0x20,
+ [Q_KEY_CODE_F] = 0x21,
+ [Q_KEY_CODE_G] = 0x22,
+ [Q_KEY_CODE_H] = 0x23,
+ [Q_KEY_CODE_J] = 0x24,
+ [Q_KEY_CODE_K] = 0x25,
+ [Q_KEY_CODE_L] = 0x26,
+ [Q_KEY_CODE_SEMICOLON] = 0x27,
+ [Q_KEY_CODE_APOSTROPHE] = 0x28,
+ [Q_KEY_CODE_GRAVE_ACCENT] = 0x29,
+
+ [Q_KEY_CODE_BACKSLASH] = 0x2b,
+ [Q_KEY_CODE_Z] = 0x2c,
+ [Q_KEY_CODE_X] = 0x2d,
+ [Q_KEY_CODE_C] = 0x2e,
+ [Q_KEY_CODE_V] = 0x2f,
+ [Q_KEY_CODE_B] = 0x30,
+ [Q_KEY_CODE_N] = 0x31,
+ [Q_KEY_CODE_M] = 0x32,
+ [Q_KEY_CODE_COMMA] = 0x33,
+ [Q_KEY_CODE_DOT] = 0x34,
+ [Q_KEY_CODE_SLASH] = 0x35,
+
+ [Q_KEY_CODE_ASTERISK] = 0x37,
+
+ [Q_KEY_CODE_SPC] = 0x39,
+ [Q_KEY_CODE_CAPS_LOCK] = 0x3a,
+ [Q_KEY_CODE_F1] = 0x3b,
+ [Q_KEY_CODE_F2] = 0x3c,
+ [Q_KEY_CODE_F3] = 0x3d,
+ [Q_KEY_CODE_F4] = 0x3e,
+ [Q_KEY_CODE_F5] = 0x3f,
+ [Q_KEY_CODE_F6] = 0x40,
+ [Q_KEY_CODE_F7] = 0x41,
+ [Q_KEY_CODE_F8] = 0x42,
+ [Q_KEY_CODE_F9] = 0x43,
+ [Q_KEY_CODE_F10] = 0x44,
+ [Q_KEY_CODE_NUM_LOCK] = 0x45,
+ [Q_KEY_CODE_SCROLL_LOCK] = 0x46,
+
+ [Q_KEY_CODE_KP_DIVIDE] = 0xb5,
+ [Q_KEY_CODE_KP_MULTIPLY] = 0x37,
+ [Q_KEY_CODE_KP_SUBTRACT] = 0x4a,
+ [Q_KEY_CODE_KP_ADD] = 0x4e,
+ [Q_KEY_CODE_KP_ENTER] = 0x9c,
+ [Q_KEY_CODE_KP_DECIMAL] = 0x53,
+ [Q_KEY_CODE_SYSRQ] = 0x54,
+
+ [Q_KEY_CODE_KP_0] = 0x52,
+ [Q_KEY_CODE_KP_1] = 0x4f,
+ [Q_KEY_CODE_KP_2] = 0x50,
+ [Q_KEY_CODE_KP_3] = 0x51,
+ [Q_KEY_CODE_KP_4] = 0x4b,
+ [Q_KEY_CODE_KP_5] = 0x4c,
+ [Q_KEY_CODE_KP_6] = 0x4d,
+ [Q_KEY_CODE_KP_7] = 0x47,
+ [Q_KEY_CODE_KP_8] = 0x48,
+ [Q_KEY_CODE_KP_9] = 0x49,
+
+ [Q_KEY_CODE_LESS] = 0x56,
+
+ [Q_KEY_CODE_F11] = 0x57,
+ [Q_KEY_CODE_F12] = 0x58,
+
+ [Q_KEY_CODE_PRINT] = 0xb7,
+
+ [Q_KEY_CODE_HOME] = 0xc7,
+ [Q_KEY_CODE_PGUP] = 0xc9,
+ [Q_KEY_CODE_PGDN] = 0xd1,
+ [Q_KEY_CODE_END] = 0xcf,
+
+ [Q_KEY_CODE_LEFT] = 0xcb,
+ [Q_KEY_CODE_UP] = 0xc8,
+ [Q_KEY_CODE_DOWN] = 0xd0,
+ [Q_KEY_CODE_RIGHT] = 0xcd,
+
+ [Q_KEY_CODE_INSERT] = 0xd2,
+ [Q_KEY_CODE_DELETE] = 0xd3,
+#ifdef NEED_CPU_H
+#if defined(TARGET_SPARC) && !defined(TARGET_SPARC64)
+ [Q_KEY_CODE_STOP] = 0xf0,
+ [Q_KEY_CODE_AGAIN] = 0xf1,
+ [Q_KEY_CODE_PROPS] = 0xf2,
+ [Q_KEY_CODE_UNDO] = 0xf3,
+ [Q_KEY_CODE_FRONT] = 0xf4,
+ [Q_KEY_CODE_COPY] = 0xf5,
+ [Q_KEY_CODE_OPEN] = 0xf6,
+ [Q_KEY_CODE_PASTE] = 0xf7,
+ [Q_KEY_CODE_FIND] = 0xf8,
+ [Q_KEY_CODE_CUT] = 0xf9,
+ [Q_KEY_CODE_LF] = 0xfa,
+ [Q_KEY_CODE_HELP] = 0xfb,
+ [Q_KEY_CODE_META_L] = 0xfc,
+ [Q_KEY_CODE_META_R] = 0xfd,
+ [Q_KEY_CODE_COMPOSE] = 0xfe,
+#endif
+#endif
+ [Q_KEY_CODE_MAX] = 0,
+};
+
+int index_from_key(const char *key)
+{
+ int i;
+
+ for (i = 0; QKeyCode_lookup[i] != NULL; i++) {
+ if (!strcmp(key, QKeyCode_lookup[i])) {
+ break;
+ }
+ }
+
+ /* Return Q_KEY_CODE_MAX if the key is invalid */
+ return i;
+}
+
+static int *keycodes;
+static int keycodes_size;
+static QEMUTimer *key_timer;
+
+static int keycode_from_keyvalue(const KeyValue *value)
+{
+ if (value->kind == KEY_VALUE_KIND_QCODE) {
+ return key_defs[value->qcode];
+ } else {
+ assert(value->kind == KEY_VALUE_KIND_NUMBER);
+ return value->number;
+ }
+}
+
+static void free_keycodes(void)
+{
+ g_free(keycodes);
+ keycodes = NULL;
+ keycodes_size = 0;
+}
+
+static void release_keys(void *opaque)
+{
+ while (keycodes_size > 0) {
+ qemu_input_event_send_key_number(NULL, keycodes[--keycodes_size],
+ false);
+ }
+
+ free_keycodes();
+}
+
+void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time,
+ Error **errp)
+{
+ int keycode;
+ KeyValueList *p;
+
+ if (!key_timer) {
+ key_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, release_keys, NULL);
+ }
+
+ if (keycodes != NULL) {
+ timer_del(key_timer);
+ release_keys(NULL);
+ }
+
+ if (!has_hold_time) {
+ hold_time = 100;
+ }
+
+ for (p = keys; p != NULL; p = p->next) {
+ /* key down events */
+ keycode = keycode_from_keyvalue(p->value);
+ if (keycode < 0x01 || keycode > 0xff) {
+ error_setg(errp, "invalid hex keycode 0x%x", keycode);
+ free_keycodes();
+ return;
+ }
+
+ qemu_input_event_send_key_number(NULL, keycode, true);
+
+ keycodes = g_realloc(keycodes, sizeof(int) * (keycodes_size + 1));
+ keycodes[keycodes_size++] = keycode;
+ }
+
+ /* delayed key up events */
+ timer_mod(key_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
+ muldiv64(get_ticks_per_sec(), hold_time, 1000));
+}
+
+static void legacy_kbd_event(DeviceState *dev, QemuConsole *src,
+ InputEvent *evt)
+{
+ QEMUPutKbdEntry *entry = (QEMUPutKbdEntry *)dev;
+ int keycode = keycode_from_keyvalue(evt->key->key);
+
+ if (!entry || !entry->put_kbd) {
+ return;
+ }
+ if (evt->key->key->kind == KEY_VALUE_KIND_QCODE &&
+ evt->key->key->qcode == Q_KEY_CODE_PAUSE) {
+ /* specific case */
+ int v = evt->key->down ? 0 : 0x80;
+ entry->put_kbd(entry->opaque, 0xe1);
+ entry->put_kbd(entry->opaque, 0x1d | v);
+ entry->put_kbd(entry->opaque, 0x45 | v);
+ return;
+ }
+ if (keycode & SCANCODE_GREY) {
+ entry->put_kbd(entry->opaque, SCANCODE_EMUL0);
+ keycode &= ~SCANCODE_GREY;
+ }
+ if (!evt->key->down) {
+ keycode |= SCANCODE_UP;
+ }
+ entry->put_kbd(entry->opaque, keycode);
+}
+
+static QemuInputHandler legacy_kbd_handler = {
+ .name = "legacy-kbd",
+ .mask = INPUT_EVENT_MASK_KEY,
+ .event = legacy_kbd_event,
+};
+
+QEMUPutKbdEntry *qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
+{
+ QEMUPutKbdEntry *entry;
+
+ entry = g_new0(QEMUPutKbdEntry, 1);
+ entry->put_kbd = func;
+ entry->opaque = opaque;
+ entry->s = qemu_input_handler_register((DeviceState *)entry,
+ &legacy_kbd_handler);
+ return entry;
+}
+
+void qemu_remove_kbd_event_handler(QEMUPutKbdEntry *entry)
+{
+ qemu_input_handler_unregister(entry->s);
+ g_free(entry);
+}
+
+static void legacy_mouse_event(DeviceState *dev, QemuConsole *src,
+ InputEvent *evt)
+{
+ static const int bmap[INPUT_BUTTON_MAX] = {
+ [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
+ [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
+ [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON,
+ };
+ QEMUPutMouseEntry *s = (QEMUPutMouseEntry *)dev;
+
+ switch (evt->kind) {
+ case INPUT_EVENT_KIND_BTN:
+ if (evt->btn->down) {
+ s->buttons |= bmap[evt->btn->button];
+ } else {
+ s->buttons &= ~bmap[evt->btn->button];
+ }
+ break;
+ case INPUT_EVENT_KIND_ABS:
+ s->axis[evt->abs->axis] = evt->abs->value;
+ break;
+ case INPUT_EVENT_KIND_REL:
+ s->axis[evt->rel->axis] += evt->rel->value;
+ break;
+ default:
+ break;
+ }
+}
+
+static void legacy_mouse_sync(DeviceState *dev)
+{
+ QEMUPutMouseEntry *s = (QEMUPutMouseEntry *)dev;
+
+ s->qemu_put_mouse_event(s->qemu_put_mouse_event_opaque,
+ s->axis[INPUT_AXIS_X],
+ s->axis[INPUT_AXIS_Y],
+ 0,
+ s->buttons);
+
+ if (!s->qemu_put_mouse_event_absolute) {
+ s->axis[INPUT_AXIS_X] = 0;
+ s->axis[INPUT_AXIS_Y] = 0;
+ }
+}
+
+QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
+ void *opaque, int absolute,
+ const char *name)
+{
+ QEMUPutMouseEntry *s;
+
+ s = g_malloc0(sizeof(QEMUPutMouseEntry));
+
+ s->qemu_put_mouse_event = func;
+ s->qemu_put_mouse_event_opaque = opaque;
+ s->qemu_put_mouse_event_absolute = absolute;
+
+ s->h.name = name;
+ s->h.mask = INPUT_EVENT_MASK_BTN |
+ (absolute ? INPUT_EVENT_MASK_ABS : INPUT_EVENT_MASK_REL);
+ s->h.event = legacy_mouse_event;
+ s->h.sync = legacy_mouse_sync;
+ s->s = qemu_input_handler_register((DeviceState *)s,
+ &s->h);
+
+ return s;
+}
+
+void qemu_activate_mouse_event_handler(QEMUPutMouseEntry *entry)
+{
+ qemu_input_handler_activate(entry->s);
+}
+
+void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry)
+{
+ qemu_input_handler_unregister(entry->s);
+
+ g_free(entry);
+}
+
+QEMUPutLEDEntry *qemu_add_led_event_handler(QEMUPutLEDEvent *func,
+ void *opaque)
+{
+ QEMUPutLEDEntry *s;
+
+ s = g_malloc0(sizeof(QEMUPutLEDEntry));
+
+ s->put_led = func;
+ s->opaque = opaque;
+ QTAILQ_INSERT_TAIL(&led_handlers, s, next);
+ return s;
+}
+
+void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry)
+{
+ if (entry == NULL)
+ return;
+ QTAILQ_REMOVE(&led_handlers, entry, next);
+ g_free(entry);
+}
+
+void kbd_put_ledstate(int ledstate)
+{
+ QEMUPutLEDEntry *cursor;
+
+ QTAILQ_FOREACH(cursor, &led_handlers, next) {
+ cursor->put_led(cursor->opaque, ledstate);
+ }
+}
diff --git a/ui/input.c b/ui/input.c
index 1c70f60e0d..2761911f3c 100644
--- a/ui/input.c
+++ b/ui/input.c
@@ -1,520 +1,333 @@
-/*
- * QEMU System Emulator
- *
- * Copyright (c) 2003-2008 Fabrice Bellard
- *
- * 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.
- */
-
#include "sysemu/sysemu.h"
-#include "monitor/monitor.h"
-#include "ui/console.h"
-#include "qapi/error.h"
-#include "qmp-commands.h"
#include "qapi-types.h"
-#include "ui/keymaps.h"
-
-struct QEMUPutMouseEntry {
- QEMUPutMouseEvent *qemu_put_mouse_event;
- void *qemu_put_mouse_event_opaque;
- int qemu_put_mouse_event_absolute;
- char *qemu_put_mouse_event_name;
-
- int index;
-
- /* used internally by qemu for handling mice */
- QTAILQ_ENTRY(QEMUPutMouseEntry) node;
-};
-
-struct QEMUPutKbdEntry {
- QEMUPutKBDEvent *put_kbd;
- void *opaque;
- QTAILQ_ENTRY(QEMUPutKbdEntry) next;
-};
+#include "qmp-commands.h"
+#include "trace.h"
+#include "ui/input.h"
+#include "ui/console.h"
-struct QEMUPutLEDEntry {
- QEMUPutLEDEvent *put_led;
- void *opaque;
- QTAILQ_ENTRY(QEMUPutLEDEntry) next;
+struct QemuInputHandlerState {
+ DeviceState *dev;
+ QemuInputHandler *handler;
+ int id;
+ int events;
+ QTAILQ_ENTRY(QemuInputHandlerState) node;
};
-
-static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers =
- QTAILQ_HEAD_INITIALIZER(led_handlers);
-static QTAILQ_HEAD(, QEMUPutKbdEntry) kbd_handlers =
- QTAILQ_HEAD_INITIALIZER(kbd_handlers);
-static QTAILQ_HEAD(, QEMUPutMouseEntry) mouse_handlers =
- QTAILQ_HEAD_INITIALIZER(mouse_handlers);
+static QTAILQ_HEAD(, QemuInputHandlerState) handlers =
+ QTAILQ_HEAD_INITIALIZER(handlers);
static NotifierList mouse_mode_notifiers =
NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers);
-static const int key_defs[] = {
- [Q_KEY_CODE_SHIFT] = 0x2a,
- [Q_KEY_CODE_SHIFT_R] = 0x36,
-
- [Q_KEY_CODE_ALT] = 0x38,
- [Q_KEY_CODE_ALT_R] = 0xb8,
- [Q_KEY_CODE_ALTGR] = 0x64,
- [Q_KEY_CODE_ALTGR_R] = 0xe4,
- [Q_KEY_CODE_CTRL] = 0x1d,
- [Q_KEY_CODE_CTRL_R] = 0x9d,
-
- [Q_KEY_CODE_MENU] = 0xdd,
-
- [Q_KEY_CODE_ESC] = 0x01,
-
- [Q_KEY_CODE_1] = 0x02,
- [Q_KEY_CODE_2] = 0x03,
- [Q_KEY_CODE_3] = 0x04,
- [Q_KEY_CODE_4] = 0x05,
- [Q_KEY_CODE_5] = 0x06,
- [Q_KEY_CODE_6] = 0x07,
- [Q_KEY_CODE_7] = 0x08,
- [Q_KEY_CODE_8] = 0x09,
- [Q_KEY_CODE_9] = 0x0a,
- [Q_KEY_CODE_0] = 0x0b,
- [Q_KEY_CODE_MINUS] = 0x0c,
- [Q_KEY_CODE_EQUAL] = 0x0d,
- [Q_KEY_CODE_BACKSPACE] = 0x0e,
-
- [Q_KEY_CODE_TAB] = 0x0f,
- [Q_KEY_CODE_Q] = 0x10,
- [Q_KEY_CODE_W] = 0x11,
- [Q_KEY_CODE_E] = 0x12,
- [Q_KEY_CODE_R] = 0x13,
- [Q_KEY_CODE_T] = 0x14,
- [Q_KEY_CODE_Y] = 0x15,
- [Q_KEY_CODE_U] = 0x16,
- [Q_KEY_CODE_I] = 0x17,
- [Q_KEY_CODE_O] = 0x18,
- [Q_KEY_CODE_P] = 0x19,
- [Q_KEY_CODE_BRACKET_LEFT] = 0x1a,
- [Q_KEY_CODE_BRACKET_RIGHT] = 0x1b,
- [Q_KEY_CODE_RET] = 0x1c,
-
- [Q_KEY_CODE_A] = 0x1e,
- [Q_KEY_CODE_S] = 0x1f,
- [Q_KEY_CODE_D] = 0x20,
- [Q_KEY_CODE_F] = 0x21,
- [Q_KEY_CODE_G] = 0x22,
- [Q_KEY_CODE_H] = 0x23,
- [Q_KEY_CODE_J] = 0x24,
- [Q_KEY_CODE_K] = 0x25,
- [Q_KEY_CODE_L] = 0x26,
- [Q_KEY_CODE_SEMICOLON] = 0x27,
- [Q_KEY_CODE_APOSTROPHE] = 0x28,
- [Q_KEY_CODE_GRAVE_ACCENT] = 0x29,
-
- [Q_KEY_CODE_BACKSLASH] = 0x2b,
- [Q_KEY_CODE_Z] = 0x2c,
- [Q_KEY_CODE_X] = 0x2d,
- [Q_KEY_CODE_C] = 0x2e,
- [Q_KEY_CODE_V] = 0x2f,
- [Q_KEY_CODE_B] = 0x30,
- [Q_KEY_CODE_N] = 0x31,
- [Q_KEY_CODE_M] = 0x32,
- [Q_KEY_CODE_COMMA] = 0x33,
- [Q_KEY_CODE_DOT] = 0x34,
- [Q_KEY_CODE_SLASH] = 0x35,
-
- [Q_KEY_CODE_ASTERISK] = 0x37,
-
- [Q_KEY_CODE_SPC] = 0x39,
- [Q_KEY_CODE_CAPS_LOCK] = 0x3a,
- [Q_KEY_CODE_F1] = 0x3b,
- [Q_KEY_CODE_F2] = 0x3c,
- [Q_KEY_CODE_F3] = 0x3d,
- [Q_KEY_CODE_F4] = 0x3e,
- [Q_KEY_CODE_F5] = 0x3f,
- [Q_KEY_CODE_F6] = 0x40,
- [Q_KEY_CODE_F7] = 0x41,
- [Q_KEY_CODE_F8] = 0x42,
- [Q_KEY_CODE_F9] = 0x43,
- [Q_KEY_CODE_F10] = 0x44,
- [Q_KEY_CODE_NUM_LOCK] = 0x45,
- [Q_KEY_CODE_SCROLL_LOCK] = 0x46,
-
- [Q_KEY_CODE_KP_DIVIDE] = 0xb5,
- [Q_KEY_CODE_KP_MULTIPLY] = 0x37,
- [Q_KEY_CODE_KP_SUBTRACT] = 0x4a,
- [Q_KEY_CODE_KP_ADD] = 0x4e,
- [Q_KEY_CODE_KP_ENTER] = 0x9c,
- [Q_KEY_CODE_KP_DECIMAL] = 0x53,
- [Q_KEY_CODE_SYSRQ] = 0x54,
-
- [Q_KEY_CODE_KP_0] = 0x52,
- [Q_KEY_CODE_KP_1] = 0x4f,
- [Q_KEY_CODE_KP_2] = 0x50,
- [Q_KEY_CODE_KP_3] = 0x51,
- [Q_KEY_CODE_KP_4] = 0x4b,
- [Q_KEY_CODE_KP_5] = 0x4c,
- [Q_KEY_CODE_KP_6] = 0x4d,
- [Q_KEY_CODE_KP_7] = 0x47,
- [Q_KEY_CODE_KP_8] = 0x48,
- [Q_KEY_CODE_KP_9] = 0x49,
-
- [Q_KEY_CODE_LESS] = 0x56,
-
- [Q_KEY_CODE_F11] = 0x57,
- [Q_KEY_CODE_F12] = 0x58,
-
- [Q_KEY_CODE_PRINT] = 0xb7,
-
- [Q_KEY_CODE_HOME] = 0xc7,
- [Q_KEY_CODE_PGUP] = 0xc9,
- [Q_KEY_CODE_PGDN] = 0xd1,
- [Q_KEY_CODE_END] = 0xcf,
-
- [Q_KEY_CODE_LEFT] = 0xcb,
- [Q_KEY_CODE_UP] = 0xc8,
- [Q_KEY_CODE_DOWN] = 0xd0,
- [Q_KEY_CODE_RIGHT] = 0xcd,
-
- [Q_KEY_CODE_INSERT] = 0xd2,
- [Q_KEY_CODE_DELETE] = 0xd3,
-#ifdef NEED_CPU_H
-#if defined(TARGET_SPARC) && !defined(TARGET_SPARC64)
- [Q_KEY_CODE_STOP] = 0xf0,
- [Q_KEY_CODE_AGAIN] = 0xf1,
- [Q_KEY_CODE_PROPS] = 0xf2,
- [Q_KEY_CODE_UNDO] = 0xf3,
- [Q_KEY_CODE_FRONT] = 0xf4,
- [Q_KEY_CODE_COPY] = 0xf5,
- [Q_KEY_CODE_OPEN] = 0xf6,
- [Q_KEY_CODE_PASTE] = 0xf7,
- [Q_KEY_CODE_FIND] = 0xf8,
- [Q_KEY_CODE_CUT] = 0xf9,
- [Q_KEY_CODE_LF] = 0xfa,
- [Q_KEY_CODE_HELP] = 0xfb,
- [Q_KEY_CODE_META_L] = 0xfc,
- [Q_KEY_CODE_META_R] = 0xfd,
- [Q_KEY_CODE_COMPOSE] = 0xfe,
-#endif
-#endif
- [Q_KEY_CODE_MAX] = 0,
-};
-
-int index_from_key(const char *key)
+QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
+ QemuInputHandler *handler)
{
- int i;
+ QemuInputHandlerState *s = g_new0(QemuInputHandlerState, 1);
+ static int id = 1;
- for (i = 0; QKeyCode_lookup[i] != NULL; i++) {
- if (!strcmp(key, QKeyCode_lookup[i])) {
- break;
- }
- }
+ s->dev = dev;
+ s->handler = handler;
+ s->id = id++;
+ QTAILQ_INSERT_TAIL(&handlers, s, node);
- /* Return Q_KEY_CODE_MAX if the key is invalid */
- return i;
+ qemu_input_check_mode_change();
+ return s;
}
-int index_from_keycode(int code)
+void qemu_input_handler_activate(QemuInputHandlerState *s)
{
- int i;
-
- for (i = 0; i < Q_KEY_CODE_MAX; i++) {
- if (key_defs[i] == code) {
- break;
- }
- }
-
- /* Return Q_KEY_CODE_MAX if the code is invalid */
- return i;
+ QTAILQ_REMOVE(&handlers, s, node);
+ QTAILQ_INSERT_HEAD(&handlers, s, node);
+ qemu_input_check_mode_change();
}
-static int *keycodes;
-static int keycodes_size;
-static QEMUTimer *key_timer;
-
-static int keycode_from_keyvalue(const KeyValue *value)
+void qemu_input_handler_unregister(QemuInputHandlerState *s)
{
- if (value->kind == KEY_VALUE_KIND_QCODE) {
- return key_defs[value->qcode];
- } else {
- assert(value->kind == KEY_VALUE_KIND_NUMBER);
- return value->number;
- }
+ QTAILQ_REMOVE(&handlers, s, node);
+ g_free(s);
+ qemu_input_check_mode_change();
}
-static void free_keycodes(void)
+static QemuInputHandlerState*
+qemu_input_find_handler(uint32_t mask)
{
- g_free(keycodes);
- keycodes = NULL;
- keycodes_size = 0;
-}
+ QemuInputHandlerState *s;
-static void release_keys(void *opaque)
-{
- while (keycodes_size > 0) {
- if (keycodes[--keycodes_size] & SCANCODE_GREY) {
- kbd_put_keycode(SCANCODE_EMUL0);
+ QTAILQ_FOREACH(s, &handlers, node) {
+ if (mask & s->handler->mask) {
+ return s;
}
- kbd_put_keycode(keycodes[keycodes_size] | SCANCODE_UP);
}
-
- free_keycodes();
+ return NULL;
}
-void qmp_send_key(KeyValueList *keys, bool has_hold_time, int64_t hold_time,
- Error **errp)
+static void qemu_input_transform_abs_rotate(InputEvent *evt)
{
- int keycode;
- KeyValueList *p;
-
- if (!key_timer) {
- key_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, release_keys, NULL);
- }
-
- if (keycodes != NULL) {
- timer_del(key_timer);
- release_keys(NULL);
- }
-
- if (!has_hold_time) {
- hold_time = 100;
- }
-
- for (p = keys; p != NULL; p = p->next) {
- /* key down events */
- keycode = keycode_from_keyvalue(p->value);
- if (keycode < 0x01 || keycode > 0xff) {
- error_setg(errp, "invalid hex keycode 0x%x", keycode);
- free_keycodes();
- return;
+ switch (graphic_rotate) {
+ case 90:
+ if (evt->abs->axis == INPUT_AXIS_X) {
+ evt->abs->axis = INPUT_AXIS_Y;
+ } else if (evt->abs->axis == INPUT_AXIS_Y) {
+ evt->abs->axis = INPUT_AXIS_X;
+ evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value;
}
-
- if (keycode & SCANCODE_GREY) {
- kbd_put_keycode(SCANCODE_EMUL0);
+ break;
+ case 180:
+ evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value;
+ break;
+ case 270:
+ if (evt->abs->axis == INPUT_AXIS_X) {
+ evt->abs->axis = INPUT_AXIS_Y;
+ evt->abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->abs->value;
+ } else if (evt->abs->axis == INPUT_AXIS_Y) {
+ evt->abs->axis = INPUT_AXIS_X;
}
- kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
-
- keycodes = g_realloc(keycodes, sizeof(int) * (keycodes_size + 1));
- keycodes[keycodes_size++] = keycode;
+ break;
}
-
- /* delayed key up events */
- timer_mod(key_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
- muldiv64(get_ticks_per_sec(), hold_time, 1000));
}
-QEMUPutKbdEntry *qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
+static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
{
- QEMUPutKbdEntry *entry;
+ const char *name;
+ int idx = -1;
- entry = g_malloc0(sizeof(QEMUPutKbdEntry));
- entry->put_kbd = func;
- entry->opaque = opaque;
- QTAILQ_INSERT_HEAD(&kbd_handlers, entry, next);
- return entry;
+ if (src) {
+ idx = qemu_console_get_index(src);
+ }
+ switch (evt->kind) {
+ case INPUT_EVENT_KIND_KEY:
+ switch (evt->key->key->kind) {
+ case KEY_VALUE_KIND_NUMBER:
+ trace_input_event_key_number(idx, evt->key->key->number,
+ evt->key->down);
+ break;
+ case KEY_VALUE_KIND_QCODE:
+ name = QKeyCode_lookup[evt->key->key->qcode];
+ trace_input_event_key_qcode(idx, name, evt->key->down);
+ break;
+ case KEY_VALUE_KIND_MAX:
+ /* keep gcc happy */
+ break;
+ }
+ break;
+ case INPUT_EVENT_KIND_BTN:
+ name = InputButton_lookup[evt->btn->button];
+ trace_input_event_btn(idx, name, evt->btn->down);
+ break;
+ case INPUT_EVENT_KIND_REL:
+ name = InputAxis_lookup[evt->rel->axis];
+ trace_input_event_rel(idx, name, evt->rel->value);
+ break;
+ case INPUT_EVENT_KIND_ABS:
+ name = InputAxis_lookup[evt->abs->axis];
+ trace_input_event_abs(idx, name, evt->abs->value);
+ break;
+ case INPUT_EVENT_KIND_MAX:
+ /* keep gcc happy */
+ break;
+ }
}
-void qemu_remove_kbd_event_handler(QEMUPutKbdEntry *entry)
+void qemu_input_event_send(QemuConsole *src, InputEvent *evt)
{
- QTAILQ_REMOVE(&kbd_handlers, entry, next);
-}
+ QemuInputHandlerState *s;
-static void check_mode_change(void)
-{
- static int current_is_absolute, current_has_absolute;
- int is_absolute;
- int has_absolute;
+ if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
+ return;
+ }
- is_absolute = kbd_mouse_is_absolute();
- has_absolute = kbd_mouse_has_absolute();
+ qemu_input_event_trace(src, evt);
- if (is_absolute != current_is_absolute ||
- has_absolute != current_has_absolute) {
- notifier_list_notify(&mouse_mode_notifiers, NULL);
+ /* pre processing */
+ if (graphic_rotate && (evt->kind == INPUT_EVENT_KIND_ABS)) {
+ qemu_input_transform_abs_rotate(evt);
}
- current_is_absolute = is_absolute;
- current_has_absolute = has_absolute;
+ /* send event */
+ s = qemu_input_find_handler(1 << evt->kind);
+ s->handler->event(s->dev, src, evt);
+ s->events++;
}
-QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func,
- void *opaque, int absolute,
- const char *name)
+void qemu_input_event_sync(void)
{
- QEMUPutMouseEntry *s;
- static int mouse_index = 0;
-
- s = g_malloc0(sizeof(QEMUPutMouseEntry));
+ QemuInputHandlerState *s;
- s->qemu_put_mouse_event = func;
- s->qemu_put_mouse_event_opaque = opaque;
- s->qemu_put_mouse_event_absolute = absolute;
- s->qemu_put_mouse_event_name = g_strdup(name);
- s->index = mouse_index++;
-
- QTAILQ_INSERT_TAIL(&mouse_handlers, s, node);
+ if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
+ return;
+ }
- check_mode_change();
+ trace_input_event_sync();
- return s;
+ QTAILQ_FOREACH(s, &handlers, node) {
+ if (!s->events) {
+ continue;
+ }
+ if (s->handler->sync) {
+ s->handler->sync(s->dev);
+ }
+ s->events = 0;
+ }
}
-void qemu_activate_mouse_event_handler(QEMUPutMouseEntry *entry)
+InputEvent *qemu_input_event_new_key(KeyValue *key, bool down)
{
- QTAILQ_REMOVE(&mouse_handlers, entry, node);
- QTAILQ_INSERT_HEAD(&mouse_handlers, entry, node);
-
- check_mode_change();
+ InputEvent *evt = g_new0(InputEvent, 1);
+ evt->key = g_new0(InputKeyEvent, 1);
+ evt->kind = INPUT_EVENT_KIND_KEY;
+ evt->key->key = key;
+ evt->key->down = down;
+ return evt;
}
-void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry)
+void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down)
{
- QTAILQ_REMOVE(&mouse_handlers, entry, node);
-
- g_free(entry->qemu_put_mouse_event_name);
- g_free(entry);
-
- check_mode_change();
+ InputEvent *evt;
+ evt = qemu_input_event_new_key(key, down);
+ qemu_input_event_send(src, evt);
+ qemu_input_event_sync();
+ qapi_free_InputEvent(evt);
}
-QEMUPutLEDEntry *qemu_add_led_event_handler(QEMUPutLEDEvent *func,
- void *opaque)
+void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down)
{
- QEMUPutLEDEntry *s;
+ KeyValue *key = g_new0(KeyValue, 1);
+ key->kind = KEY_VALUE_KIND_NUMBER;
+ key->number = num;
+ qemu_input_event_send_key(src, key, down);
+}
- s = g_malloc0(sizeof(QEMUPutLEDEntry));
+void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down)
+{
+ KeyValue *key = g_new0(KeyValue, 1);
+ key->kind = KEY_VALUE_KIND_QCODE;
+ key->qcode = q;
+ qemu_input_event_send_key(src, key, down);
+}
- s->put_led = func;
- s->opaque = opaque;
- QTAILQ_INSERT_TAIL(&led_handlers, s, next);
- return s;
+InputEvent *qemu_input_event_new_btn(InputButton btn, bool down)
+{
+ InputEvent *evt = g_new0(InputEvent, 1);
+ evt->btn = g_new0(InputBtnEvent, 1);
+ evt->kind = INPUT_EVENT_KIND_BTN;
+ evt->btn->button = btn;
+ evt->btn->down = down;
+ return evt;
}
-void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry)
+void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down)
{
- if (entry == NULL)
- return;
- QTAILQ_REMOVE(&led_handlers, entry, next);
- g_free(entry);
+ InputEvent *evt;
+ evt = qemu_input_event_new_btn(btn, down);
+ qemu_input_event_send(src, evt);
+ qapi_free_InputEvent(evt);
}
-void kbd_put_keycode(int keycode)
+void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map,
+ uint32_t button_old, uint32_t button_new)
{
- QEMUPutKbdEntry *entry = QTAILQ_FIRST(&kbd_handlers);
+ InputButton btn;
+ uint32_t mask;
- if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
- return;
- }
- if (entry && entry->put_kbd) {
- entry->put_kbd(entry->opaque, keycode);
+ for (btn = 0; btn < INPUT_BUTTON_MAX; btn++) {
+ mask = button_map[btn];
+ if ((button_old & mask) == (button_new & mask)) {
+ continue;
+ }
+ qemu_input_queue_btn(src, btn, button_new & mask);
}
}
-void kbd_put_ledstate(int ledstate)
+bool qemu_input_is_absolute(void)
{
- QEMUPutLEDEntry *cursor;
+ QemuInputHandlerState *s;
- QTAILQ_FOREACH(cursor, &led_handlers, next) {
- cursor->put_led(cursor->opaque, ledstate);
- }
+ s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS);
+ return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS);
}
-void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
+int qemu_input_scale_axis(int value, int size_in, int size_out)
{
- QEMUPutMouseEntry *entry;
- QEMUPutMouseEvent *mouse_event;
- void *mouse_event_opaque;
- int width, height;
-
- if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
- return;
+ if (size_in < 2) {
+ return size_out / 2;
}
- if (QTAILQ_EMPTY(&mouse_handlers)) {
- return;
- }
-
- entry = QTAILQ_FIRST(&mouse_handlers);
+ return (int64_t)value * (size_out - 1) / (size_in - 1);
+}
- mouse_event = entry->qemu_put_mouse_event;
- mouse_event_opaque = entry->qemu_put_mouse_event_opaque;
+InputEvent *qemu_input_event_new_move(InputEventKind kind,
+ InputAxis axis, int value)
+{
+ InputEvent *evt = g_new0(InputEvent, 1);
+ InputMoveEvent *move = g_new0(InputMoveEvent, 1);
+
+ evt->kind = kind;
+ evt->data = move;
+ move->axis = axis;
+ move->value = value;
+ return evt;
+}
- if (mouse_event) {
- if (entry->qemu_put_mouse_event_absolute) {
- width = 0x7fff;
- height = 0x7fff;
- } else {
- width = graphic_width - 1;
- height = graphic_height - 1;
- }
+void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value)
+{
+ InputEvent *evt;
+ evt = qemu_input_event_new_move(INPUT_EVENT_KIND_REL, axis, value);
+ qemu_input_event_send(src, evt);
+ qapi_free_InputEvent(evt);
+}
- switch (graphic_rotate) {
- case 0:
- mouse_event(mouse_event_opaque,
- dx, dy, dz, buttons_state);
- break;
- case 90:
- mouse_event(mouse_event_opaque,
- width - dy, dx, dz, buttons_state);
- break;
- case 180:
- mouse_event(mouse_event_opaque,
- width - dx, height - dy, dz, buttons_state);
- break;
- case 270:
- mouse_event(mouse_event_opaque,
- dy, height - dx, dz, buttons_state);
- break;
- }
- }
+void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value, int size)
+{
+ InputEvent *evt;
+ int scaled = qemu_input_scale_axis(value, size, INPUT_EVENT_ABS_SIZE);
+ evt = qemu_input_event_new_move(INPUT_EVENT_KIND_ABS, axis, scaled);
+ qemu_input_event_send(src, evt);
+ qapi_free_InputEvent(evt);
}
-int kbd_mouse_is_absolute(void)
+void qemu_input_check_mode_change(void)
{
- if (QTAILQ_EMPTY(&mouse_handlers)) {
- return 0;
+ static int current_is_absolute;
+ int is_absolute;
+
+ is_absolute = qemu_input_is_absolute();
+
+ if (is_absolute != current_is_absolute) {
+ trace_input_mouse_mode(is_absolute);
+ notifier_list_notify(&mouse_mode_notifiers, NULL);
}
- return QTAILQ_FIRST(&mouse_handlers)->qemu_put_mouse_event_absolute;
+ current_is_absolute = is_absolute;
}
-int kbd_mouse_has_absolute(void)
+void qemu_add_mouse_mode_change_notifier(Notifier *notify)
{
- QEMUPutMouseEntry *entry;
-
- QTAILQ_FOREACH(entry, &mouse_handlers, node) {
- if (entry->qemu_put_mouse_event_absolute) {
- return 1;
- }
- }
+ notifier_list_add(&mouse_mode_notifiers, notify);
+}
- return 0;
+void qemu_remove_mouse_mode_change_notifier(Notifier *notify)
+{
+ notifier_remove(notify);
}
MouseInfoList *qmp_query_mice(Error **errp)
{
MouseInfoList *mice_list = NULL;
- QEMUPutMouseEntry *cursor;
+ MouseInfoList *info;
+ QemuInputHandlerState *s;
bool current = true;
- QTAILQ_FOREACH(cursor, &mouse_handlers, node) {
- MouseInfoList *info = g_malloc0(sizeof(*info));
- info->value = g_malloc0(sizeof(*info->value));
- info->value->name = g_strdup(cursor->qemu_put_mouse_event_name);
- info->value->index = cursor->index;
- info->value->absolute = !!cursor->qemu_put_mouse_event_absolute;
+ QTAILQ_FOREACH(s, &handlers, node) {
+ if (!(s->handler->mask &
+ (INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS))) {
+ continue;
+ }
+
+ info = g_new0(MouseInfoList, 1);
+ info->value = g_new0(MouseInfo, 1);
+ info->value->index = s->id;
+ info->value->name = g_strdup(s->handler->name);
+ info->value->absolute = s->handler->mask & INPUT_EVENT_MASK_ABS;
info->value->current = current;
current = false;
-
info->next = mice_list;
mice_list = info;
}
@@ -524,19 +337,14 @@ MouseInfoList *qmp_query_mice(Error **errp)
void do_mouse_set(Monitor *mon, const QDict *qdict)
{
- QEMUPutMouseEntry *cursor;
+ QemuInputHandlerState *s;
int index = qdict_get_int(qdict, "index");
int found = 0;
- if (QTAILQ_EMPTY(&mouse_handlers)) {
- monitor_printf(mon, "No mouse devices connected\n");
- return;
- }
-
- QTAILQ_FOREACH(cursor, &mouse_handlers, node) {
- if (cursor->index == index) {
+ QTAILQ_FOREACH(s, &handlers, node) {
+ if (s->id == index) {
found = 1;
- qemu_activate_mouse_event_handler(cursor);
+ qemu_input_handler_activate(s);
break;
}
}
@@ -545,15 +353,5 @@ void do_mouse_set(Monitor *mon, const QDict *qdict)
monitor_printf(mon, "Mouse at given index not found\n");
}
- check_mode_change();
-}
-
-void qemu_add_mouse_mode_change_notifier(Notifier *notify)
-{
- notifier_list_add(&mouse_mode_notifiers, notify);
-}
-
-void qemu_remove_mouse_mode_change_notifier(Notifier *notify)
-{
- notifier_remove(notify);
+ qemu_input_check_mode_change();
}
diff --git a/ui/sdl.c b/ui/sdl.c
index 9d8583c4e6..c1a16bebdc 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -26,10 +26,13 @@
#undef WIN32_LEAN_AND_MEAN
#include <SDL.h>
+
+#if SDL_MAJOR_VERSION == 1
#include <SDL_syswm.h>
#include "qemu-common.h"
#include "ui/console.h"
+#include "ui/input.h"
#include "sysemu/sysemu.h"
#include "x_keymap.h"
#include "sdl_zoom.h"
@@ -261,9 +264,7 @@ static void reset_keys(void)
int i;
for(i = 0; i < 256; i++) {
if (modifiers_state[i]) {
- if (i & SCANCODE_GREY)
- kbd_put_keycode(SCANCODE_EMUL0);
- kbd_put_keycode(i | SCANCODE_UP);
+ qemu_input_event_send_key_number(dcl->con, i, false);
modifiers_state[i] = 0;
}
}
@@ -271,16 +272,12 @@ static void reset_keys(void)
static void sdl_process_key(SDL_KeyboardEvent *ev)
{
- int keycode, v;
+ int keycode;
if (ev->keysym.sym == SDLK_PAUSE) {
/* specific case */
- v = 0;
- if (ev->type == SDL_KEYUP)
- v |= SCANCODE_UP;
- kbd_put_keycode(0xe1);
- kbd_put_keycode(0x1d | v);
- kbd_put_keycode(0x45 | v);
+ qemu_input_event_send_key_qcode(dcl->con, Q_KEY_CODE_PAUSE,
+ ev->type == SDL_KEYDOWN);
return;
}
@@ -312,19 +309,15 @@ static void sdl_process_key(SDL_KeyboardEvent *ev)
case 0x45: /* num lock */
case 0x3a: /* caps lock */
/* SDL does not send the key up event, so we generate it */
- kbd_put_keycode(keycode);
- kbd_put_keycode(keycode | SCANCODE_UP);
+ qemu_input_event_send_key_number(dcl->con, keycode, true);
+ qemu_input_event_send_key_number(dcl->con, keycode, false);
return;
#endif
}
/* now send the key code */
- if (keycode & SCANCODE_GREY)
- kbd_put_keycode(SCANCODE_EMUL0);
- if (ev->type == SDL_KEYUP)
- kbd_put_keycode(keycode | SCANCODE_UP);
- else
- kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
+ qemu_input_event_send_key_number(dcl->con, keycode,
+ ev->type == SDL_KEYDOWN);
}
static void sdl_update_caption(void)
@@ -360,7 +353,7 @@ static void sdl_hide_cursor(void)
if (!cursor_hide)
return;
- if (kbd_mouse_is_absolute()) {
+ if (qemu_input_is_absolute()) {
SDL_ShowCursor(1);
SDL_SetCursor(sdl_cursor_hidden);
} else {
@@ -373,10 +366,10 @@ static void sdl_show_cursor(void)
if (!cursor_hide)
return;
- if (!kbd_mouse_is_absolute() || !qemu_console_is_graphic(NULL)) {
+ if (!qemu_input_is_absolute() || !qemu_console_is_graphic(NULL)) {
SDL_ShowCursor(1);
if (guest_cursor &&
- (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
+ (gui_grab || qemu_input_is_absolute() || absolute_enabled))
SDL_SetCursor(guest_sprite);
else
SDL_SetCursor(sdl_cursor_normal);
@@ -395,8 +388,9 @@ static void sdl_grab_start(void)
}
if (guest_cursor) {
SDL_SetCursor(guest_sprite);
- if (!kbd_mouse_is_absolute() && !absolute_enabled)
+ if (!qemu_input_is_absolute() && !absolute_enabled) {
SDL_WarpMouse(guest_x, guest_y);
+ }
} else
sdl_hide_cursor();
SDL_WM_GrabInput(SDL_GRAB_ON);
@@ -425,7 +419,7 @@ static void absolute_mouse_grab(void)
static void sdl_mouse_mode_change(Notifier *notify, void *data)
{
- if (kbd_mouse_is_absolute()) {
+ if (qemu_input_is_absolute()) {
if (!absolute_enabled) {
absolute_enabled = 1;
if (qemu_console_is_graphic(NULL)) {
@@ -440,33 +434,36 @@ static void sdl_mouse_mode_change(Notifier *notify, void *data)
}
}
-static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state)
+static void sdl_send_mouse_event(int dx, int dy, int x, int y, int state)
{
- int buttons = 0;
-
- if (state & SDL_BUTTON(SDL_BUTTON_LEFT)) {
- buttons |= MOUSE_EVENT_LBUTTON;
- }
- if (state & SDL_BUTTON(SDL_BUTTON_RIGHT)) {
- buttons |= MOUSE_EVENT_RBUTTON;
- }
- if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) {
- buttons |= MOUSE_EVENT_MBUTTON;
- }
-
- if (kbd_mouse_is_absolute()) {
- dx = x * 0x7FFF / (real_screen->w - 1);
- dy = y * 0x7FFF / (real_screen->h - 1);
+ static uint32_t bmap[INPUT_BUTTON_MAX] = {
+ [INPUT_BUTTON_LEFT] = SDL_BUTTON(SDL_BUTTON_LEFT),
+ [INPUT_BUTTON_MIDDLE] = SDL_BUTTON(SDL_BUTTON_MIDDLE),
+ [INPUT_BUTTON_RIGHT] = SDL_BUTTON(SDL_BUTTON_RIGHT),
+ [INPUT_BUTTON_WHEEL_UP] = SDL_BUTTON(SDL_BUTTON_WHEELUP),
+ [INPUT_BUTTON_WHEEL_DOWN] = SDL_BUTTON(SDL_BUTTON_WHEELDOWN),
+ };
+ static uint32_t prev_state;
+
+ if (prev_state != state) {
+ qemu_input_update_buttons(dcl->con, bmap, prev_state, state);
+ prev_state = state;
+ }
+
+ if (qemu_input_is_absolute()) {
+ qemu_input_queue_abs(dcl->con, INPUT_AXIS_X, x,
+ real_screen->w);
+ qemu_input_queue_abs(dcl->con, INPUT_AXIS_Y, y,
+ real_screen->h);
} else if (guest_cursor) {
x -= guest_x;
y -= guest_y;
guest_x += x;
guest_y += y;
- dx = x;
- dy = y;
+ qemu_input_queue_rel(dcl->con, INPUT_AXIS_X, x);
+ qemu_input_queue_rel(dcl->con, INPUT_AXIS_Y, y);
}
-
- kbd_mouse_event(dx, dy, dz, buttons);
+ qemu_input_event_sync();
}
static void sdl_scale(int width, int height)
@@ -694,7 +691,7 @@ static void handle_mousemotion(SDL_Event *ev)
int max_x, max_y;
if (qemu_console_is_graphic(NULL) &&
- (kbd_mouse_is_absolute() || absolute_enabled)) {
+ (qemu_input_is_absolute() || absolute_enabled)) {
max_x = real_screen->w - 1;
max_y = real_screen->h - 1;
if (gui_grab && (ev->motion.x == 0 || ev->motion.y == 0 ||
@@ -707,8 +704,8 @@ static void handle_mousemotion(SDL_Event *ev)
sdl_grab_start();
}
}
- if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) {
- sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel, 0,
+ if (gui_grab || qemu_input_is_absolute() || absolute_enabled) {
+ sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel,
ev->motion.x, ev->motion.y, ev->motion.state);
}
}
@@ -717,35 +714,24 @@ static void handle_mousebutton(SDL_Event *ev)
{
int buttonstate = SDL_GetMouseState(NULL, NULL);
SDL_MouseButtonEvent *bev;
- int dz;
if (!qemu_console_is_graphic(NULL)) {
return;
}
bev = &ev->button;
- if (!gui_grab && !kbd_mouse_is_absolute()) {
+ if (!gui_grab && !qemu_input_is_absolute()) {
if (ev->type == SDL_MOUSEBUTTONUP && bev->button == SDL_BUTTON_LEFT) {
/* start grabbing all events */
sdl_grab_start();
}
} else {
- dz = 0;
if (ev->type == SDL_MOUSEBUTTONDOWN) {
buttonstate |= SDL_BUTTON(bev->button);
} else {
buttonstate &= ~SDL_BUTTON(bev->button);
}
-#ifdef SDL_BUTTON_WHEELUP
- if (bev->button == SDL_BUTTON_WHEELUP &&
- ev->type == SDL_MOUSEBUTTONDOWN) {
- dz = -1;
- } else if (bev->button == SDL_BUTTON_WHEELDOWN &&
- ev->type == SDL_MOUSEBUTTONDOWN) {
- dz = 1;
- }
-#endif
- sdl_send_mouse_event(0, 0, dz, bev->x, bev->y, buttonstate);
+ sdl_send_mouse_event(0, 0, bev->x, bev->y, buttonstate);
}
}
@@ -760,7 +746,7 @@ static void handle_activation(SDL_Event *ev)
}
#endif
if (!gui_grab && ev->active.gain && qemu_console_is_graphic(NULL) &&
- (kbd_mouse_is_absolute() || absolute_enabled)) {
+ (qemu_input_is_absolute() || absolute_enabled)) {
absolute_mouse_grab();
}
if (ev->active.state & SDL_APPACTIVE) {
@@ -832,10 +818,11 @@ static void sdl_mouse_warp(DisplayChangeListener *dcl,
if (on) {
if (!guest_cursor)
sdl_show_cursor();
- if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) {
+ if (gui_grab || qemu_input_is_absolute() || absolute_enabled) {
SDL_SetCursor(guest_sprite);
- if (!kbd_mouse_is_absolute() && !absolute_enabled)
+ if (!qemu_input_is_absolute() && !absolute_enabled) {
SDL_WarpMouse(x, y);
+ }
}
} else if (gui_grab)
sdl_hide_cursor();
@@ -863,7 +850,7 @@ static void sdl_mouse_define(DisplayChangeListener *dcl,
g_free(mask);
if (guest_cursor &&
- (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
+ (gui_grab || qemu_input_is_absolute() || absolute_enabled))
SDL_SetCursor(guest_sprite);
}
@@ -966,3 +953,4 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
atexit(sdl_cleanup);
}
+#endif
diff --git a/ui/sdl2-keymap.h b/ui/sdl2-keymap.h
new file mode 100644
index 0000000000..5a12f4543a
--- /dev/null
+++ b/ui/sdl2-keymap.h
@@ -0,0 +1,266 @@
+
+/* map SDL2 scancodes to QKeyCode */
+
+static const int sdl2_scancode_to_qcode[SDL_NUM_SCANCODES] = {
+ [SDL_SCANCODE_A] = Q_KEY_CODE_A,
+ [SDL_SCANCODE_B] = Q_KEY_CODE_B,
+ [SDL_SCANCODE_C] = Q_KEY_CODE_C,
+ [SDL_SCANCODE_D] = Q_KEY_CODE_D,
+ [SDL_SCANCODE_E] = Q_KEY_CODE_E,
+ [SDL_SCANCODE_F] = Q_KEY_CODE_F,
+ [SDL_SCANCODE_G] = Q_KEY_CODE_G,
+ [SDL_SCANCODE_H] = Q_KEY_CODE_H,
+ [SDL_SCANCODE_I] = Q_KEY_CODE_I,
+ [SDL_SCANCODE_J] = Q_KEY_CODE_J,
+ [SDL_SCANCODE_K] = Q_KEY_CODE_K,
+ [SDL_SCANCODE_L] = Q_KEY_CODE_L,
+ [SDL_SCANCODE_M] = Q_KEY_CODE_M,
+ [SDL_SCANCODE_N] = Q_KEY_CODE_N,
+ [SDL_SCANCODE_O] = Q_KEY_CODE_O,
+ [SDL_SCANCODE_P] = Q_KEY_CODE_P,
+ [SDL_SCANCODE_Q] = Q_KEY_CODE_Q,
+ [SDL_SCANCODE_R] = Q_KEY_CODE_R,
+ [SDL_SCANCODE_S] = Q_KEY_CODE_S,
+ [SDL_SCANCODE_T] = Q_KEY_CODE_T,
+ [SDL_SCANCODE_U] = Q_KEY_CODE_U,
+ [SDL_SCANCODE_V] = Q_KEY_CODE_V,
+ [SDL_SCANCODE_W] = Q_KEY_CODE_W,
+ [SDL_SCANCODE_X] = Q_KEY_CODE_X,
+ [SDL_SCANCODE_Y] = Q_KEY_CODE_Y,
+ [SDL_SCANCODE_Z] = Q_KEY_CODE_Z,
+
+ [SDL_SCANCODE_1] = Q_KEY_CODE_1,
+ [SDL_SCANCODE_2] = Q_KEY_CODE_2,
+ [SDL_SCANCODE_3] = Q_KEY_CODE_3,
+ [SDL_SCANCODE_4] = Q_KEY_CODE_4,
+ [SDL_SCANCODE_5] = Q_KEY_CODE_5,
+ [SDL_SCANCODE_6] = Q_KEY_CODE_6,
+ [SDL_SCANCODE_7] = Q_KEY_CODE_7,
+ [SDL_SCANCODE_8] = Q_KEY_CODE_8,
+ [SDL_SCANCODE_9] = Q_KEY_CODE_9,
+ [SDL_SCANCODE_0] = Q_KEY_CODE_0,
+
+ [SDL_SCANCODE_RETURN] = Q_KEY_CODE_RET,
+ [SDL_SCANCODE_ESCAPE] = Q_KEY_CODE_ESC,
+ [SDL_SCANCODE_BACKSPACE] = Q_KEY_CODE_BACKSPACE,
+ [SDL_SCANCODE_TAB] = Q_KEY_CODE_TAB,
+ [SDL_SCANCODE_SPACE] = Q_KEY_CODE_SPC,
+ [SDL_SCANCODE_MINUS] = Q_KEY_CODE_MINUS,
+ [SDL_SCANCODE_EQUALS] = Q_KEY_CODE_EQUAL,
+ [SDL_SCANCODE_LEFTBRACKET] = Q_KEY_CODE_BRACKET_LEFT,
+ [SDL_SCANCODE_RIGHTBRACKET] = Q_KEY_CODE_BRACKET_RIGHT,
+ [SDL_SCANCODE_BACKSLASH] = Q_KEY_CODE_BACKSLASH,
+#if 0
+ [SDL_SCANCODE_NONUSHASH] = Q_KEY_CODE_NONUSHASH,
+#endif
+ [SDL_SCANCODE_SEMICOLON] = Q_KEY_CODE_SEMICOLON,
+ [SDL_SCANCODE_APOSTROPHE] = Q_KEY_CODE_APOSTROPHE,
+ [SDL_SCANCODE_GRAVE] = Q_KEY_CODE_GRAVE_ACCENT,
+ [SDL_SCANCODE_COMMA] = Q_KEY_CODE_COMMA,
+ [SDL_SCANCODE_PERIOD] = Q_KEY_CODE_DOT,
+ [SDL_SCANCODE_SLASH] = Q_KEY_CODE_SLASH,
+ [SDL_SCANCODE_CAPSLOCK] = Q_KEY_CODE_CAPS_LOCK,
+
+ [SDL_SCANCODE_F1] = Q_KEY_CODE_F1,
+ [SDL_SCANCODE_F2] = Q_KEY_CODE_F2,
+ [SDL_SCANCODE_F3] = Q_KEY_CODE_F3,
+ [SDL_SCANCODE_F4] = Q_KEY_CODE_F4,
+ [SDL_SCANCODE_F5] = Q_KEY_CODE_F5,
+ [SDL_SCANCODE_F6] = Q_KEY_CODE_F6,
+ [SDL_SCANCODE_F7] = Q_KEY_CODE_F7,
+ [SDL_SCANCODE_F8] = Q_KEY_CODE_F8,
+ [SDL_SCANCODE_F9] = Q_KEY_CODE_F9,
+ [SDL_SCANCODE_F10] = Q_KEY_CODE_F10,
+ [SDL_SCANCODE_F11] = Q_KEY_CODE_F11,
+ [SDL_SCANCODE_F12] = Q_KEY_CODE_F12,
+
+ [SDL_SCANCODE_PRINTSCREEN] = Q_KEY_CODE_PRINT,
+ [SDL_SCANCODE_SCROLLLOCK] = Q_KEY_CODE_SCROLL_LOCK,
+ [SDL_SCANCODE_PAUSE] = Q_KEY_CODE_PAUSE,
+ [SDL_SCANCODE_INSERT] = Q_KEY_CODE_INSERT,
+ [SDL_SCANCODE_HOME] = Q_KEY_CODE_HOME,
+ [SDL_SCANCODE_PAGEUP] = Q_KEY_CODE_PGUP,
+ [SDL_SCANCODE_DELETE] = Q_KEY_CODE_DELETE,
+ [SDL_SCANCODE_END] = Q_KEY_CODE_END,
+ [SDL_SCANCODE_PAGEDOWN] = Q_KEY_CODE_PGDN,
+ [SDL_SCANCODE_RIGHT] = Q_KEY_CODE_RIGHT,
+ [SDL_SCANCODE_LEFT] = Q_KEY_CODE_LEFT,
+ [SDL_SCANCODE_DOWN] = Q_KEY_CODE_DOWN,
+ [SDL_SCANCODE_UP] = Q_KEY_CODE_UP,
+ [SDL_SCANCODE_NUMLOCKCLEAR] = Q_KEY_CODE_NUM_LOCK,
+
+ [SDL_SCANCODE_KP_DIVIDE] = Q_KEY_CODE_KP_DIVIDE,
+ [SDL_SCANCODE_KP_MULTIPLY] = Q_KEY_CODE_KP_MULTIPLY,
+ [SDL_SCANCODE_KP_MINUS] = Q_KEY_CODE_KP_SUBTRACT,
+ [SDL_SCANCODE_KP_PLUS] = Q_KEY_CODE_KP_ADD,
+ [SDL_SCANCODE_KP_ENTER] = Q_KEY_CODE_KP_ENTER,
+ [SDL_SCANCODE_KP_1] = Q_KEY_CODE_KP_1,
+ [SDL_SCANCODE_KP_2] = Q_KEY_CODE_KP_2,
+ [SDL_SCANCODE_KP_3] = Q_KEY_CODE_KP_3,
+ [SDL_SCANCODE_KP_4] = Q_KEY_CODE_KP_4,
+ [SDL_SCANCODE_KP_5] = Q_KEY_CODE_KP_5,
+ [SDL_SCANCODE_KP_6] = Q_KEY_CODE_KP_6,
+ [SDL_SCANCODE_KP_7] = Q_KEY_CODE_KP_7,
+ [SDL_SCANCODE_KP_8] = Q_KEY_CODE_KP_8,
+ [SDL_SCANCODE_KP_9] = Q_KEY_CODE_KP_9,
+ [SDL_SCANCODE_KP_0] = Q_KEY_CODE_KP_0,
+ [SDL_SCANCODE_KP_PERIOD] = Q_KEY_CODE_KP_DECIMAL,
+#if 0
+ [SDL_SCANCODE_NONUSBACKSLASH] = Q_KEY_CODE_NONUSBACKSLASH,
+ [SDL_SCANCODE_APPLICATION] = Q_KEY_CODE_APPLICATION,
+ [SDL_SCANCODE_POWER] = Q_KEY_CODE_POWER,
+ [SDL_SCANCODE_KP_EQUALS] = Q_KEY_CODE_KP_EQUALS,
+
+ [SDL_SCANCODE_F13] = Q_KEY_CODE_F13,
+ [SDL_SCANCODE_F14] = Q_KEY_CODE_F14,
+ [SDL_SCANCODE_F15] = Q_KEY_CODE_F15,
+ [SDL_SCANCODE_F16] = Q_KEY_CODE_F16,
+ [SDL_SCANCODE_F17] = Q_KEY_CODE_F17,
+ [SDL_SCANCODE_F18] = Q_KEY_CODE_F18,
+ [SDL_SCANCODE_F19] = Q_KEY_CODE_F19,
+ [SDL_SCANCODE_F20] = Q_KEY_CODE_F20,
+ [SDL_SCANCODE_F21] = Q_KEY_CODE_F21,
+ [SDL_SCANCODE_F22] = Q_KEY_CODE_F22,
+ [SDL_SCANCODE_F23] = Q_KEY_CODE_F23,
+ [SDL_SCANCODE_F24] = Q_KEY_CODE_F24,
+
+ [SDL_SCANCODE_EXECUTE] = Q_KEY_CODE_EXECUTE,
+#endif
+ [SDL_SCANCODE_HELP] = Q_KEY_CODE_HELP,
+ [SDL_SCANCODE_MENU] = Q_KEY_CODE_MENU,
+#if 0
+ [SDL_SCANCODE_SELECT] = Q_KEY_CODE_SELECT,
+#endif
+ [SDL_SCANCODE_STOP] = Q_KEY_CODE_STOP,
+ [SDL_SCANCODE_AGAIN] = Q_KEY_CODE_AGAIN,
+ [SDL_SCANCODE_UNDO] = Q_KEY_CODE_UNDO,
+ [SDL_SCANCODE_CUT] = Q_KEY_CODE_CUT,
+ [SDL_SCANCODE_COPY] = Q_KEY_CODE_COPY,
+ [SDL_SCANCODE_PASTE] = Q_KEY_CODE_PASTE,
+ [SDL_SCANCODE_FIND] = Q_KEY_CODE_FIND,
+#if 0
+ [SDL_SCANCODE_MUTE] = Q_KEY_CODE_MUTE,
+ [SDL_SCANCODE_VOLUMEUP] = Q_KEY_CODE_VOLUMEUP,
+ [SDL_SCANCODE_VOLUMEDOWN] = Q_KEY_CODE_VOLUMEDOWN,
+
+ [SDL_SCANCODE_KP_COMMA] = Q_KEY_CODE_KP_COMMA,
+ [SDL_SCANCODE_KP_EQUALSAS400] = Q_KEY_CODE_KP_EQUALSAS400,
+
+ [SDL_SCANCODE_INTERNATIONAL1] = Q_KEY_CODE_INTERNATIONAL1,
+ [SDL_SCANCODE_INTERNATIONAL2] = Q_KEY_CODE_INTERNATIONAL2,
+ [SDL_SCANCODE_INTERNATIONAL3] = Q_KEY_CODE_INTERNATIONAL3,
+ [SDL_SCANCODE_INTERNATIONAL4] = Q_KEY_CODE_INTERNATIONAL4,
+ [SDL_SCANCODE_INTERNATIONAL5] = Q_KEY_CODE_INTERNATIONAL5,
+ [SDL_SCANCODE_INTERNATIONAL6] = Q_KEY_CODE_INTERNATIONAL6,
+ [SDL_SCANCODE_INTERNATIONAL7] = Q_KEY_CODE_INTERNATIONAL7,
+ [SDL_SCANCODE_INTERNATIONAL8] = Q_KEY_CODE_INTERNATIONAL8,
+ [SDL_SCANCODE_INTERNATIONAL9] = Q_KEY_CODE_INTERNATIONAL9,
+ [SDL_SCANCODE_LANG1] = Q_KEY_CODE_LANG1,
+ [SDL_SCANCODE_LANG2] = Q_KEY_CODE_LANG2,
+ [SDL_SCANCODE_LANG3] = Q_KEY_CODE_LANG3,
+ [SDL_SCANCODE_LANG4] = Q_KEY_CODE_LANG4,
+ [SDL_SCANCODE_LANG5] = Q_KEY_CODE_LANG5,
+ [SDL_SCANCODE_LANG6] = Q_KEY_CODE_LANG6,
+ [SDL_SCANCODE_LANG7] = Q_KEY_CODE_LANG7,
+ [SDL_SCANCODE_LANG8] = Q_KEY_CODE_LANG8,
+ [SDL_SCANCODE_LANG9] = Q_KEY_CODE_LANG9,
+ [SDL_SCANCODE_ALTERASE] = Q_KEY_CODE_ALTERASE,
+#endif
+ [SDL_SCANCODE_SYSREQ] = Q_KEY_CODE_SYSRQ,
+#if 0
+ [SDL_SCANCODE_CANCEL] = Q_KEY_CODE_CANCEL,
+ [SDL_SCANCODE_CLEAR] = Q_KEY_CODE_CLEAR,
+ [SDL_SCANCODE_PRIOR] = Q_KEY_CODE_PRIOR,
+ [SDL_SCANCODE_RETURN2] = Q_KEY_CODE_RETURN2,
+ [SDL_SCANCODE_SEPARATOR] = Q_KEY_CODE_SEPARATOR,
+ [SDL_SCANCODE_OUT] = Q_KEY_CODE_OUT,
+ [SDL_SCANCODE_OPER] = Q_KEY_CODE_OPER,
+ [SDL_SCANCODE_CLEARAGAIN] = Q_KEY_CODE_CLEARAGAIN,
+ [SDL_SCANCODE_CRSEL] = Q_KEY_CODE_CRSEL,
+ [SDL_SCANCODE_EXSEL] = Q_KEY_CODE_EXSEL,
+ [SDL_SCANCODE_KP_00] = Q_KEY_CODE_KP_00,
+ [SDL_SCANCODE_KP_000] = Q_KEY_CODE_KP_000,
+ [SDL_SCANCODE_THOUSANDSSEPARATOR] = Q_KEY_CODE_THOUSANDSSEPARATOR,
+ [SDL_SCANCODE_DECIMALSEPARATOR] = Q_KEY_CODE_DECIMALSEPARATOR,
+ [SDL_SCANCODE_CURRENCYUNIT] = Q_KEY_CODE_CURRENCYUNIT,
+ [SDL_SCANCODE_CURRENCYSUBUNIT] = Q_KEY_CODE_CURRENCYSUBUNIT,
+ [SDL_SCANCODE_KP_LEFTPAREN] = Q_KEY_CODE_KP_LEFTPAREN,
+ [SDL_SCANCODE_KP_RIGHTPAREN] = Q_KEY_CODE_KP_RIGHTPAREN,
+ [SDL_SCANCODE_KP_LEFTBRACE] = Q_KEY_CODE_KP_LEFTBRACE,
+ [SDL_SCANCODE_KP_RIGHTBRACE] = Q_KEY_CODE_KP_RIGHTBRACE,
+ [SDL_SCANCODE_KP_TAB] = Q_KEY_CODE_KP_TAB,
+ [SDL_SCANCODE_KP_BACKSPACE] = Q_KEY_CODE_KP_BACKSPACE,
+ [SDL_SCANCODE_KP_A] = Q_KEY_CODE_KP_A,
+ [SDL_SCANCODE_KP_B] = Q_KEY_CODE_KP_B,
+ [SDL_SCANCODE_KP_C] = Q_KEY_CODE_KP_C,
+ [SDL_SCANCODE_KP_D] = Q_KEY_CODE_KP_D,
+ [SDL_SCANCODE_KP_E] = Q_KEY_CODE_KP_E,
+ [SDL_SCANCODE_KP_F] = Q_KEY_CODE_KP_F,
+ [SDL_SCANCODE_KP_XOR] = Q_KEY_CODE_KP_XOR,
+ [SDL_SCANCODE_KP_POWER] = Q_KEY_CODE_KP_POWER,
+ [SDL_SCANCODE_KP_PERCENT] = Q_KEY_CODE_KP_PERCENT,
+ [SDL_SCANCODE_KP_LESS] = Q_KEY_CODE_KP_LESS,
+ [SDL_SCANCODE_KP_GREATER] = Q_KEY_CODE_KP_GREATER,
+ [SDL_SCANCODE_KP_AMPERSAND] = Q_KEY_CODE_KP_AMPERSAND,
+ [SDL_SCANCODE_KP_DBLAMPERSAND] = Q_KEY_CODE_KP_DBLAMPERSAND,
+ [SDL_SCANCODE_KP_VERTICALBAR] = Q_KEY_CODE_KP_VERTICALBAR,
+ [SDL_SCANCODE_KP_DBLVERTICALBAR] = Q_KEY_CODE_KP_DBLVERTICALBAR,
+ [SDL_SCANCODE_KP_COLON] = Q_KEY_CODE_KP_COLON,
+ [SDL_SCANCODE_KP_HASH] = Q_KEY_CODE_KP_HASH,
+ [SDL_SCANCODE_KP_SPACE] = Q_KEY_CODE_KP_SPACE,
+ [SDL_SCANCODE_KP_AT] = Q_KEY_CODE_KP_AT,
+ [SDL_SCANCODE_KP_EXCLAM] = Q_KEY_CODE_KP_EXCLAM,
+ [SDL_SCANCODE_KP_MEMSTORE] = Q_KEY_CODE_KP_MEMSTORE,
+ [SDL_SCANCODE_KP_MEMRECALL] = Q_KEY_CODE_KP_MEMRECALL,
+ [SDL_SCANCODE_KP_MEMCLEAR] = Q_KEY_CODE_KP_MEMCLEAR,
+ [SDL_SCANCODE_KP_MEMADD] = Q_KEY_CODE_KP_MEMADD,
+ [SDL_SCANCODE_KP_MEMSUBTRACT] = Q_KEY_CODE_KP_MEMSUBTRACT,
+ [SDL_SCANCODE_KP_MEMMULTIPLY] = Q_KEY_CODE_KP_MEMMULTIPLY,
+ [SDL_SCANCODE_KP_MEMDIVIDE] = Q_KEY_CODE_KP_MEMDIVIDE,
+ [SDL_SCANCODE_KP_PLUSMINUS] = Q_KEY_CODE_KP_PLUSMINUS,
+ [SDL_SCANCODE_KP_CLEAR] = Q_KEY_CODE_KP_CLEAR,
+ [SDL_SCANCODE_KP_CLEARENTRY] = Q_KEY_CODE_KP_CLEARENTRY,
+ [SDL_SCANCODE_KP_BINARY] = Q_KEY_CODE_KP_BINARY,
+ [SDL_SCANCODE_KP_OCTAL] = Q_KEY_CODE_KP_OCTAL,
+ [SDL_SCANCODE_KP_DECIMAL] = Q_KEY_CODE_KP_DECIMAL,
+ [SDL_SCANCODE_KP_HEXADECIMAL] = Q_KEY_CODE_KP_HEXADECIMAL,
+#endif
+ [SDL_SCANCODE_LCTRL] = Q_KEY_CODE_CTRL,
+ [SDL_SCANCODE_LSHIFT] = Q_KEY_CODE_SHIFT,
+ [SDL_SCANCODE_LALT] = Q_KEY_CODE_ALT,
+ [SDL_SCANCODE_LGUI] = Q_KEY_CODE_META_L,
+ [SDL_SCANCODE_RCTRL] = Q_KEY_CODE_CTRL_R,
+ [SDL_SCANCODE_RSHIFT] = Q_KEY_CODE_SHIFT_R,
+ [SDL_SCANCODE_RALT] = Q_KEY_CODE_ALTGR,
+ [SDL_SCANCODE_RGUI] = Q_KEY_CODE_META_R,
+#if 0
+ [SDL_SCANCODE_MODE] = Q_KEY_CODE_MODE,
+ [SDL_SCANCODE_AUDIONEXT] = Q_KEY_CODE_AUDIONEXT,
+ [SDL_SCANCODE_AUDIOPREV] = Q_KEY_CODE_AUDIOPREV,
+ [SDL_SCANCODE_AUDIOSTOP] = Q_KEY_CODE_AUDIOSTOP,
+ [SDL_SCANCODE_AUDIOPLAY] = Q_KEY_CODE_AUDIOPLAY,
+ [SDL_SCANCODE_AUDIOMUTE] = Q_KEY_CODE_AUDIOMUTE,
+ [SDL_SCANCODE_MEDIASELECT] = Q_KEY_CODE_MEDIASELECT,
+ [SDL_SCANCODE_WWW] = Q_KEY_CODE_WWW,
+ [SDL_SCANCODE_MAIL] = Q_KEY_CODE_MAIL,
+ [SDL_SCANCODE_CALCULATOR] = Q_KEY_CODE_CALCULATOR,
+ [SDL_SCANCODE_COMPUTER] = Q_KEY_CODE_COMPUTER,
+ [SDL_SCANCODE_AC_SEARCH] = Q_KEY_CODE_AC_SEARCH,
+ [SDL_SCANCODE_AC_HOME] = Q_KEY_CODE_AC_HOME,
+ [SDL_SCANCODE_AC_BACK] = Q_KEY_CODE_AC_BACK,
+ [SDL_SCANCODE_AC_FORWARD] = Q_KEY_CODE_AC_FORWARD,
+ [SDL_SCANCODE_AC_STOP] = Q_KEY_CODE_AC_STOP,
+ [SDL_SCANCODE_AC_REFRESH] = Q_KEY_CODE_AC_REFRESH,
+ [SDL_SCANCODE_AC_BOOKMARKS] = Q_KEY_CODE_AC_BOOKMARKS,
+ [SDL_SCANCODE_BRIGHTNESSDOWN] = Q_KEY_CODE_BRIGHTNESSDOWN,
+ [SDL_SCANCODE_BRIGHTNESSUP] = Q_KEY_CODE_BRIGHTNESSUP,
+ [SDL_SCANCODE_DISPLAYSWITCH] = Q_KEY_CODE_DISPLAYSWITCH,
+ [SDL_SCANCODE_KBDILLUMTOGGLE] = Q_KEY_CODE_KBDILLUMTOGGLE,
+ [SDL_SCANCODE_KBDILLUMDOWN] = Q_KEY_CODE_KBDILLUMDOWN,
+ [SDL_SCANCODE_KBDILLUMUP] = Q_KEY_CODE_KBDILLUMUP,
+ [SDL_SCANCODE_EJECT] = Q_KEY_CODE_EJECT,
+ [SDL_SCANCODE_SLEEP] = Q_KEY_CODE_SLEEP,
+ [SDL_SCANCODE_APP1] = Q_KEY_CODE_APP1,
+ [SDL_SCANCODE_APP2] = Q_KEY_CODE_APP2,
+#endif
+};
diff --git a/ui/sdl2.c b/ui/sdl2.c
new file mode 100644
index 0000000000..f1532e9d2c
--- /dev/null
+++ b/ui/sdl2.c
@@ -0,0 +1,829 @@
+/*
+ * QEMU SDL display driver
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * 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.
+ */
+/* Ported SDL 1.2 code to 2.0 by Dave Airlie. */
+
+/* Avoid compiler warning because macro is redefined in SDL_syswm.h. */
+#undef WIN32_LEAN_AND_MEAN
+
+#include <SDL.h>
+
+#if SDL_MAJOR_VERSION == 2
+#include <SDL_syswm.h>
+
+#include "qemu-common.h"
+#include "ui/console.h"
+#include "ui/input.h"
+#include "sysemu/sysemu.h"
+#include "sdl_zoom.h"
+
+#include "sdl2-keymap.h"
+
+static int sdl2_num_outputs;
+static struct sdl2_state {
+ DisplayChangeListener dcl;
+ DisplaySurface *surface;
+ SDL_Texture *texture;
+ SDL_Window *real_window;
+ SDL_Renderer *real_renderer;
+ int idx;
+ int last_vm_running; /* per console for caption reasons */
+ int x, y;
+} *sdl2_console;
+
+static SDL_Surface *guest_sprite_surface;
+static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
+
+static bool gui_saved_scaling;
+static int gui_saved_width;
+static int gui_saved_height;
+static int gui_saved_grab;
+static int gui_fullscreen;
+static int gui_noframe;
+static int gui_key_modifier_pressed;
+static int gui_keysym;
+static int gui_grab_code = KMOD_LALT | KMOD_LCTRL;
+static uint8_t modifiers_state[SDL_NUM_SCANCODES];
+static SDL_Cursor *sdl_cursor_normal;
+static SDL_Cursor *sdl_cursor_hidden;
+static int absolute_enabled;
+static int guest_cursor;
+static int guest_x, guest_y;
+static SDL_Cursor *guest_sprite;
+static int scaling_active;
+static Notifier mouse_mode_notifier;
+
+static void sdl_update_caption(struct sdl2_state *scon);
+
+static struct sdl2_state *get_scon_from_window(uint32_t window_id)
+{
+ int i;
+ for (i = 0; i < sdl2_num_outputs; i++) {
+ if (sdl2_console[i].real_window == SDL_GetWindowFromID(window_id)) {
+ return &sdl2_console[i];
+ }
+ }
+ return NULL;
+}
+
+static void sdl_update(DisplayChangeListener *dcl,
+ int x, int y, int w, int h)
+{
+ struct sdl2_state *scon = container_of(dcl, struct sdl2_state, dcl);
+ SDL_Rect rect;
+ DisplaySurface *surf = qemu_console_surface(dcl->con);
+
+ if (!surf) {
+ return;
+ }
+ if (!scon->texture) {
+ return;
+ }
+
+ rect.x = x;
+ rect.y = y;
+ rect.w = w;
+ rect.h = h;
+
+ SDL_UpdateTexture(scon->texture, NULL, surface_data(surf),
+ surface_stride(surf));
+ SDL_RenderCopy(scon->real_renderer, scon->texture, &rect, &rect);
+ SDL_RenderPresent(scon->real_renderer);
+}
+
+static void do_sdl_resize(struct sdl2_state *scon, int width, int height,
+ int bpp)
+{
+ int flags;
+
+ if (scon->real_window && scon->real_renderer) {
+ if (width && height) {
+ SDL_RenderSetLogicalSize(scon->real_renderer, width, height);
+ SDL_SetWindowSize(scon->real_window, width, height);
+ } else {
+ SDL_DestroyRenderer(scon->real_renderer);
+ SDL_DestroyWindow(scon->real_window);
+ scon->real_renderer = NULL;
+ scon->real_window = NULL;
+ }
+ } else {
+ if (!width || !height) {
+ return;
+ }
+ flags = 0;
+ if (gui_fullscreen) {
+ flags |= SDL_WINDOW_FULLSCREEN;
+ } else {
+ flags |= SDL_WINDOW_RESIZABLE;
+ }
+
+ scon->real_window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED,
+ SDL_WINDOWPOS_UNDEFINED,
+ width, height, flags);
+ scon->real_renderer = SDL_CreateRenderer(scon->real_window, -1, 0);
+ sdl_update_caption(scon);
+ }
+}
+
+static void sdl_switch(DisplayChangeListener *dcl,
+ DisplaySurface *new_surface)
+{
+ struct sdl2_state *scon = container_of(dcl, struct sdl2_state, dcl);
+ int format = 0;
+ int idx = scon->idx;
+ DisplaySurface *old_surface = scon->surface;
+
+ /* temporary hack: allows to call sdl_switch to handle scaling changes */
+ if (new_surface) {
+ scon->surface = new_surface;
+ }
+
+ if (!new_surface && idx > 0) {
+ scon->surface = NULL;
+ }
+
+ if (new_surface == NULL) {
+ do_sdl_resize(scon, 0, 0, 0);
+ } else {
+ do_sdl_resize(scon, surface_width(scon->surface),
+ surface_height(scon->surface), 0);
+ }
+
+ if (old_surface && scon->texture) {
+ SDL_DestroyTexture(scon->texture);
+ scon->texture = NULL;
+ }
+
+ if (new_surface) {
+ if (!scon->texture) {
+ if (surface_bits_per_pixel(scon->surface) == 16) {
+ format = SDL_PIXELFORMAT_RGB565;
+ } else if (surface_bits_per_pixel(scon->surface) == 32) {
+ format = SDL_PIXELFORMAT_ARGB8888;
+ }
+
+ scon->texture = SDL_CreateTexture(scon->real_renderer, format,
+ SDL_TEXTUREACCESS_STREAMING,
+ surface_width(new_surface),
+ surface_height(new_surface));
+ }
+ }
+}
+
+static void reset_keys(void)
+{
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ if (modifiers_state[i]) {
+ int qcode = sdl2_scancode_to_qcode[i];
+ qemu_input_event_send_key_qcode(NULL, qcode, false);
+ modifiers_state[i] = 0;
+ }
+ }
+}
+
+static void sdl_process_key(SDL_KeyboardEvent *ev)
+{
+ int qcode = sdl2_scancode_to_qcode[ev->keysym.scancode];
+
+ switch (ev->keysym.scancode) {
+#if 0
+ case SDL_SCANCODE_NUMLOCKCLEAR:
+ case SDL_SCANCODE_CAPSLOCK:
+ /* SDL does not send the key up event, so we generate it */
+ qemu_input_event_send_key_qcode(NULL, qcode, true);
+ qemu_input_event_send_key_qcode(NULL, qcode, false);
+ return;
+#endif
+ case SDL_SCANCODE_LCTRL:
+ case SDL_SCANCODE_LSHIFT:
+ case SDL_SCANCODE_LALT:
+ case SDL_SCANCODE_LGUI:
+ case SDL_SCANCODE_RCTRL:
+ case SDL_SCANCODE_RSHIFT:
+ case SDL_SCANCODE_RALT:
+ case SDL_SCANCODE_RGUI:
+ if (ev->type == SDL_KEYUP) {
+ modifiers_state[ev->keysym.scancode] = 0;
+ } else {
+ modifiers_state[ev->keysym.scancode] = 1;
+ }
+ /* fall though */
+ default:
+ qemu_input_event_send_key_qcode(NULL, qcode,
+ ev->type == SDL_KEYDOWN);
+ }
+}
+
+static void sdl_update_caption(struct sdl2_state *scon)
+{
+ char win_title[1024];
+ char icon_title[1024];
+ const char *status = "";
+
+ if (!runstate_is_running()) {
+ status = " [Stopped]";
+ } else if (gui_grab) {
+ if (alt_grab) {
+ status = " - Press Ctrl-Alt-Shift to exit mouse grab";
+ } else if (ctrl_grab) {
+ status = " - Press Right-Ctrl to exit mouse grab";
+ } else {
+ status = " - Press Ctrl-Alt to exit mouse grab";
+ }
+ }
+
+ if (qemu_name) {
+ snprintf(win_title, sizeof(win_title), "QEMU (%s-%d)%s", qemu_name,
+ scon->idx, status);
+ snprintf(icon_title, sizeof(icon_title), "QEMU (%s)", qemu_name);
+ } else {
+ snprintf(win_title, sizeof(win_title), "QEMU%s", status);
+ snprintf(icon_title, sizeof(icon_title), "QEMU");
+ }
+
+ if (scon->real_window) {
+ SDL_SetWindowTitle(scon->real_window, win_title);
+ }
+}
+
+static void sdl_hide_cursor(void)
+{
+ if (!cursor_hide) {
+ return;
+ }
+
+ if (qemu_input_is_absolute()) {
+ SDL_ShowCursor(1);
+ SDL_SetCursor(sdl_cursor_hidden);
+ } else {
+ SDL_ShowCursor(0);
+ }
+}
+
+static void sdl_show_cursor(void)
+{
+ if (!cursor_hide) {
+ return;
+ }
+
+ if (!qemu_input_is_absolute()) {
+ SDL_ShowCursor(1);
+ if (guest_cursor &&
+ (gui_grab || qemu_input_is_absolute() || absolute_enabled)) {
+ SDL_SetCursor(guest_sprite);
+ } else {
+ SDL_SetCursor(sdl_cursor_normal);
+ }
+ }
+}
+
+static void sdl_grab_start(struct sdl2_state *scon)
+{
+ /*
+ * If the application is not active, do not try to enter grab state. This
+ * prevents 'SDL_WM_GrabInput(SDL_GRAB_ON)' from blocking all the
+ * application (SDL bug).
+ */
+ if (!(SDL_GetWindowFlags(scon->real_window) & SDL_WINDOW_INPUT_FOCUS)) {
+ return;
+ }
+ if (guest_cursor) {
+ SDL_SetCursor(guest_sprite);
+ if (!qemu_input_is_absolute() && !absolute_enabled) {
+ SDL_WarpMouseInWindow(scon->real_window, guest_x, guest_y);
+ }
+ } else {
+ sdl_hide_cursor();
+ }
+ SDL_SetWindowGrab(scon->real_window, SDL_TRUE);
+ gui_grab = 1;
+ sdl_update_caption(scon);
+}
+
+static void sdl_grab_end(struct sdl2_state *scon)
+{
+ SDL_SetWindowGrab(scon->real_window, SDL_FALSE);
+ gui_grab = 0;
+ sdl_show_cursor();
+ sdl_update_caption(scon);
+}
+
+static void absolute_mouse_grab(struct sdl2_state *scon)
+{
+ int mouse_x, mouse_y;
+ int scr_w, scr_h;
+ SDL_GetMouseState(&mouse_x, &mouse_y);
+ SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h);
+ if (mouse_x > 0 && mouse_x < scr_w - 1 &&
+ mouse_y > 0 && mouse_y < scr_h - 1) {
+ sdl_grab_start(scon);
+ }
+}
+
+static void sdl_mouse_mode_change(Notifier *notify, void *data)
+{
+ if (qemu_input_is_absolute()) {
+ if (!absolute_enabled) {
+ absolute_enabled = 1;
+ absolute_mouse_grab(&sdl2_console[0]);
+ }
+ } else if (absolute_enabled) {
+ if (!gui_fullscreen) {
+ sdl_grab_end(&sdl2_console[0]);
+ }
+ absolute_enabled = 0;
+ }
+}
+
+static void sdl_send_mouse_event(struct sdl2_state *scon, int dx, int dy,
+ int dz, int x, int y, int state)
+{
+ static uint32_t bmap[INPUT_BUTTON_MAX] = {
+ [INPUT_BUTTON_LEFT] = SDL_BUTTON(SDL_BUTTON_LEFT),
+ [INPUT_BUTTON_MIDDLE] = SDL_BUTTON(SDL_BUTTON_MIDDLE),
+ [INPUT_BUTTON_RIGHT] = SDL_BUTTON(SDL_BUTTON_RIGHT),
+#if 0
+ [INPUT_BUTTON_WHEEL_UP] = SDL_BUTTON(SDL_BUTTON_WHEELUP),
+ [INPUT_BUTTON_WHEEL_DOWN] = SDL_BUTTON(SDL_BUTTON_WHEELDOWN),
+#endif
+ };
+ static uint32_t prev_state;
+
+ if (prev_state != state) {
+ qemu_input_update_buttons(scon->dcl.con, bmap, prev_state, state);
+ prev_state = state;
+ }
+
+ if (qemu_input_is_absolute()) {
+ int scr_w, scr_h;
+ int max_w = 0, max_h = 0;
+ int off_x = 0, off_y = 0;
+ int cur_off_x = 0, cur_off_y = 0;
+ int i;
+
+ for (i = 0; i < sdl2_num_outputs; i++) {
+ struct sdl2_state *thiscon = &sdl2_console[i];
+ if (thiscon->real_window && thiscon->surface) {
+ SDL_GetWindowSize(thiscon->real_window, &scr_w, &scr_h);
+ cur_off_x = thiscon->x;
+ cur_off_y = thiscon->y;
+ if (scr_w + cur_off_x > max_w) {
+ max_w = scr_w + cur_off_x;
+ }
+ if (scr_h + cur_off_y > max_h) {
+ max_h = scr_h + cur_off_y;
+ }
+ if (i == scon->idx) {
+ off_x = cur_off_x;
+ off_y = cur_off_y;
+ }
+ }
+ }
+ qemu_input_queue_abs(scon->dcl.con, INPUT_AXIS_X, off_x + x, max_w);
+ qemu_input_queue_abs(scon->dcl.con, INPUT_AXIS_Y, off_y + y, max_h);
+ } else if (guest_cursor) {
+ x -= guest_x;
+ y -= guest_y;
+ guest_x += x;
+ guest_y += y;
+ qemu_input_queue_rel(scon->dcl.con, INPUT_AXIS_X, x);
+ qemu_input_queue_rel(scon->dcl.con, INPUT_AXIS_Y, y);
+ }
+ qemu_input_event_sync();
+}
+
+static void sdl_scale(struct sdl2_state *scon, int width, int height)
+{
+ int bpp = 0;
+ do_sdl_resize(scon, width, height, bpp);
+ scaling_active = 1;
+}
+
+static void toggle_full_screen(struct sdl2_state *scon)
+{
+ int width = surface_width(scon->surface);
+ int height = surface_height(scon->surface);
+ int bpp = surface_bits_per_pixel(scon->surface);
+
+ gui_fullscreen = !gui_fullscreen;
+ if (gui_fullscreen) {
+ SDL_GetWindowSize(scon->real_window,
+ &gui_saved_width, &gui_saved_height);
+ gui_saved_scaling = scaling_active;
+
+ do_sdl_resize(scon, width, height, bpp);
+ scaling_active = 0;
+
+ gui_saved_grab = gui_grab;
+ sdl_grab_start(scon);
+ } else {
+ if (gui_saved_scaling) {
+ sdl_scale(scon, gui_saved_width, gui_saved_height);
+ } else {
+ do_sdl_resize(scon, width, height, 0);
+ }
+ if (!gui_saved_grab) {
+ sdl_grab_end(scon);
+ }
+ }
+ graphic_hw_invalidate(scon->dcl.con);
+ graphic_hw_update(scon->dcl.con);
+}
+
+static void handle_keydown(SDL_Event *ev)
+{
+ int mod_state;
+ struct sdl2_state *scon = get_scon_from_window(ev->key.windowID);
+
+ if (alt_grab) {
+ mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) ==
+ (gui_grab_code | KMOD_LSHIFT);
+ } else if (ctrl_grab) {
+ mod_state = (SDL_GetModState() & KMOD_RCTRL) == KMOD_RCTRL;
+ } else {
+ mod_state = (SDL_GetModState() & gui_grab_code) == gui_grab_code;
+ }
+ gui_key_modifier_pressed = mod_state;
+
+ if (gui_key_modifier_pressed) {
+ switch (ev->key.keysym.scancode) {
+ case SDL_SCANCODE_F:
+ toggle_full_screen(scon);
+ gui_keysym = 1;
+ break;
+ case SDL_SCANCODE_U:
+ if (scaling_active) {
+ scaling_active = 0;
+ sdl_switch(&scon->dcl, NULL);
+ graphic_hw_invalidate(scon->dcl.con);
+ graphic_hw_update(scon->dcl.con);
+ }
+ gui_keysym = 1;
+ break;
+ case SDL_SCANCODE_KP_PLUS:
+ case SDL_SCANCODE_KP_MINUS:
+ if (!gui_fullscreen) {
+ int scr_w, scr_h;
+ int width, height;
+ SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h);
+
+ width = MAX(scr_w + (ev->key.keysym.scancode ==
+ SDL_SCANCODE_KP_PLUS ? 50 : -50),
+ 160);
+ height = (surface_height(scon->surface) * width) /
+ surface_width(scon->surface);
+
+ sdl_scale(scon, width, height);
+ graphic_hw_invalidate(NULL);
+ graphic_hw_update(NULL);
+ gui_keysym = 1;
+ }
+ default:
+ break;
+ }
+ }
+ if (!gui_keysym) {
+ sdl_process_key(&ev->key);
+ }
+}
+
+static void handle_keyup(SDL_Event *ev)
+{
+ int mod_state;
+ struct sdl2_state *scon = get_scon_from_window(ev->key.windowID);
+
+ if (!alt_grab) {
+ mod_state = (ev->key.keysym.mod & gui_grab_code);
+ } else {
+ mod_state = (ev->key.keysym.mod & (gui_grab_code | KMOD_LSHIFT));
+ }
+ if (!mod_state && gui_key_modifier_pressed) {
+ gui_key_modifier_pressed = 0;
+ if (gui_keysym == 0) {
+ /* exit/enter grab if pressing Ctrl-Alt */
+ if (!gui_grab) {
+ sdl_grab_start(scon);
+ } else if (!gui_fullscreen) {
+ sdl_grab_end(scon);
+ }
+ /* SDL does not send back all the modifiers key, so we must
+ * correct it. */
+ reset_keys();
+ return;
+ }
+ gui_keysym = 0;
+ }
+ if (!gui_keysym) {
+ sdl_process_key(&ev->key);
+ }
+}
+
+static void handle_mousemotion(SDL_Event *ev)
+{
+ int max_x, max_y;
+ struct sdl2_state *scon = get_scon_from_window(ev->key.windowID);
+
+ if (qemu_input_is_absolute() || absolute_enabled) {
+ int scr_w, scr_h;
+ SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h);
+ max_x = scr_w - 1;
+ max_y = scr_h - 1;
+ if (gui_grab && (ev->motion.x == 0 || ev->motion.y == 0 ||
+ ev->motion.x == max_x || ev->motion.y == max_y)) {
+ sdl_grab_end(scon);
+ }
+ if (!gui_grab &&
+ (ev->motion.x > 0 && ev->motion.x < max_x &&
+ ev->motion.y > 0 && ev->motion.y < max_y)) {
+ sdl_grab_start(scon);
+ }
+ }
+ if (gui_grab || qemu_input_is_absolute() || absolute_enabled) {
+ sdl_send_mouse_event(scon, ev->motion.xrel, ev->motion.yrel, 0,
+ ev->motion.x, ev->motion.y, ev->motion.state);
+ }
+}
+
+static void handle_mousebutton(SDL_Event *ev)
+{
+ int buttonstate = SDL_GetMouseState(NULL, NULL);
+ SDL_MouseButtonEvent *bev;
+ struct sdl2_state *scon = get_scon_from_window(ev->key.windowID);
+ int dz;
+
+ bev = &ev->button;
+ if (!gui_grab && !qemu_input_is_absolute()) {
+ if (ev->type == SDL_MOUSEBUTTONUP && bev->button == SDL_BUTTON_LEFT) {
+ /* start grabbing all events */
+ sdl_grab_start(scon);
+ }
+ } else {
+ dz = 0;
+ if (ev->type == SDL_MOUSEBUTTONDOWN) {
+ buttonstate |= SDL_BUTTON(bev->button);
+ } else {
+ buttonstate &= ~SDL_BUTTON(bev->button);
+ }
+#ifdef SDL_BUTTON_WHEELUP
+ if (bev->button == SDL_BUTTON_WHEELUP &&
+ ev->type == SDL_MOUSEBUTTONDOWN) {
+ dz = -1;
+ } else if (bev->button == SDL_BUTTON_WHEELDOWN &&
+ ev->type == SDL_MOUSEBUTTONDOWN) {
+ dz = 1;
+ }
+#endif
+ sdl_send_mouse_event(scon, 0, 0, dz, bev->x, bev->y, buttonstate);
+ }
+}
+
+static void handle_windowevent(DisplayChangeListener *dcl, SDL_Event *ev)
+{
+ int w, h;
+ struct sdl2_state *scon = get_scon_from_window(ev->key.windowID);
+
+ switch (ev->window.event) {
+ case SDL_WINDOWEVENT_RESIZED:
+ sdl_scale(scon, ev->window.data1, ev->window.data2);
+ graphic_hw_invalidate(scon->dcl.con);
+ graphic_hw_update(scon->dcl.con);
+ break;
+ case SDL_WINDOWEVENT_EXPOSED:
+ SDL_GetWindowSize(SDL_GetWindowFromID(ev->window.windowID), &w, &h);
+ sdl_update(dcl, 0, 0, w, h);
+ break;
+ case SDL_WINDOWEVENT_FOCUS_GAINED:
+ case SDL_WINDOWEVENT_ENTER:
+ if (!gui_grab && (qemu_input_is_absolute() || absolute_enabled)) {
+ absolute_mouse_grab(scon);
+ }
+ break;
+ case SDL_WINDOWEVENT_FOCUS_LOST:
+ if (gui_grab && !gui_fullscreen) {
+ sdl_grab_end(scon);
+ }
+ break;
+ case SDL_WINDOWEVENT_RESTORED:
+ update_displaychangelistener(dcl, GUI_REFRESH_INTERVAL_DEFAULT);
+ break;
+ case SDL_WINDOWEVENT_MINIMIZED:
+ update_displaychangelistener(dcl, 500);
+ break;
+ case SDL_WINDOWEVENT_CLOSE:
+ if (!no_quit) {
+ no_shutdown = 0;
+ qemu_system_shutdown_request();
+ }
+ break;
+ }
+}
+
+static void sdl_refresh(DisplayChangeListener *dcl)
+{
+ struct sdl2_state *scon = container_of(dcl, struct sdl2_state, dcl);
+ SDL_Event ev1, *ev = &ev1;
+
+ if (scon->last_vm_running != runstate_is_running()) {
+ scon->last_vm_running = runstate_is_running();
+ sdl_update_caption(scon);
+ }
+
+ graphic_hw_update(dcl->con);
+
+ while (SDL_PollEvent(ev)) {
+ switch (ev->type) {
+ case SDL_KEYDOWN:
+ handle_keydown(ev);
+ break;
+ case SDL_KEYUP:
+ handle_keyup(ev);
+ break;
+ case SDL_QUIT:
+ if (!no_quit) {
+ no_shutdown = 0;
+ qemu_system_shutdown_request();
+ }
+ break;
+ case SDL_MOUSEMOTION:
+ handle_mousemotion(ev);
+ break;
+ case SDL_MOUSEBUTTONDOWN:
+ case SDL_MOUSEBUTTONUP:
+ handle_mousebutton(ev);
+ break;
+ case SDL_WINDOWEVENT:
+ handle_windowevent(dcl, ev);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void sdl_mouse_warp(DisplayChangeListener *dcl,
+ int x, int y, int on)
+{
+ struct sdl2_state *scon = container_of(dcl, struct sdl2_state, dcl);
+ if (on) {
+ if (!guest_cursor) {
+ sdl_show_cursor();
+ }
+ if (gui_grab || qemu_input_is_absolute() || absolute_enabled) {
+ SDL_SetCursor(guest_sprite);
+ if (!qemu_input_is_absolute() && !absolute_enabled) {
+ SDL_WarpMouseInWindow(scon->real_window, x, y);
+ }
+ }
+ } else if (gui_grab) {
+ sdl_hide_cursor();
+ }
+ guest_cursor = on;
+ guest_x = x, guest_y = y;
+}
+
+static void sdl_mouse_define(DisplayChangeListener *dcl,
+ QEMUCursor *c)
+{
+
+ if (guest_sprite) {
+ SDL_FreeCursor(guest_sprite);
+ }
+
+ if (guest_sprite_surface) {
+ SDL_FreeSurface(guest_sprite_surface);
+ }
+
+ guest_sprite_surface =
+ SDL_CreateRGBSurfaceFrom(c->data, c->width, c->height, 32, c->width * 4,
+ 0xff0000, 0x00ff00, 0xff, 0xff000000);
+
+ if (!guest_sprite_surface) {
+ fprintf(stderr, "Failed to make rgb surface from %p\n", c);
+ return;
+ }
+ guest_sprite = SDL_CreateColorCursor(guest_sprite_surface,
+ c->hot_x, c->hot_y);
+ if (!guest_sprite) {
+ fprintf(stderr, "Failed to make color cursor from %p\n", c);
+ return;
+ }
+ if (guest_cursor &&
+ (gui_grab || qemu_input_is_absolute() || absolute_enabled)) {
+ SDL_SetCursor(guest_sprite);
+ }
+}
+
+static void sdl_cleanup(void)
+{
+ if (guest_sprite) {
+ SDL_FreeCursor(guest_sprite);
+ }
+ SDL_QuitSubSystem(SDL_INIT_VIDEO);
+}
+
+static const DisplayChangeListenerOps dcl_ops = {
+ .dpy_name = "sdl",
+ .dpy_gfx_update = sdl_update,
+ .dpy_gfx_switch = sdl_switch,
+ .dpy_refresh = sdl_refresh,
+ .dpy_mouse_set = sdl_mouse_warp,
+ .dpy_cursor_define = sdl_mouse_define,
+};
+
+void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
+{
+ int flags;
+ uint8_t data = 0;
+ char *filename;
+ int i;
+
+ if (no_frame) {
+ gui_noframe = 1;
+ }
+
+#ifdef __linux__
+ /* on Linux, SDL may use fbcon|directfb|svgalib when run without
+ * accessible $DISPLAY to open X11 window. This is often the case
+ * when qemu is run using sudo. But in this case, and when actually
+ * run in X11 environment, SDL fights with X11 for the video card,
+ * making current display unavailable, often until reboot.
+ * So make x11 the default SDL video driver if this variable is unset.
+ * This is a bit hackish but saves us from bigger problem.
+ * Maybe it's a good idea to fix this in SDL instead.
+ */
+ setenv("SDL_VIDEODRIVER", "x11", 0);
+#endif
+
+ flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
+ if (SDL_Init(flags)) {
+ fprintf(stderr, "Could not initialize SDL(%s) - exiting\n",
+ SDL_GetError());
+ exit(1);
+ }
+
+ for (i = 0;; i++) {
+ QemuConsole *con = qemu_console_lookup_by_index(i);
+ if (!con || !qemu_console_is_graphic(con)) {
+ break;
+ }
+ }
+ sdl2_num_outputs = i;
+ sdl2_console = g_new0(struct sdl2_state, sdl2_num_outputs);
+ for (i = 0; i < sdl2_num_outputs; i++) {
+ QemuConsole *con = qemu_console_lookup_by_index(i);
+ sdl2_console[i].dcl.ops = &dcl_ops;
+ sdl2_console[i].dcl.con = con;
+ register_displaychangelistener(&sdl2_console[i].dcl);
+ sdl2_console[i].idx = i;
+ }
+
+ /* Load a 32x32x4 image. White pixels are transparent. */
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "qemu-icon.bmp");
+ if (filename) {
+ SDL_Surface *image = SDL_LoadBMP(filename);
+ if (image) {
+ uint32_t colorkey = SDL_MapRGB(image->format, 255, 255, 255);
+ SDL_SetColorKey(image, SDL_TRUE, colorkey);
+ SDL_SetWindowIcon(sdl2_console[0].real_window, image);
+ }
+ g_free(filename);
+ }
+
+ if (full_screen) {
+ gui_fullscreen = 1;
+ sdl_grab_start(0);
+ }
+
+ mouse_mode_notifier.notify = sdl_mouse_mode_change;
+ qemu_add_mouse_mode_change_notifier(&mouse_mode_notifier);
+
+ gui_grab = 0;
+
+ sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0);
+ sdl_cursor_normal = SDL_GetCursor();
+
+ atexit(sdl_cleanup);
+}
+#endif
diff --git a/ui/sdl_keysym.h b/ui/sdl_keysym.h
index ee904805da..599d9fc64d 100644
--- a/ui/sdl_keysym.h
+++ b/ui/sdl_keysym.h
@@ -200,6 +200,7 @@ static const name2keysym_t name2keysym[]={
{ "yacute", 0x0fd},
{ "thorn", 0x0fe},
{ "ydiaeresis", 0x0ff},
+#if SDL_MAJOR_VERSION == 1
{"EuroSign", SDLK_EURO},
/* modifiers */
@@ -272,6 +273,6 @@ static const name2keysym_t name2keysym[]={
{"Num_Lock", SDLK_NUMLOCK},
{"Pause", SDLK_PAUSE},
{"Escape", SDLK_ESCAPE},
-
+#endif
{NULL, 0},
};
diff --git a/ui/spice-input.c b/ui/spice-input.c
index 3beb8deadb..6dab23b75c 100644
--- a/ui/spice-input.c
+++ b/ui/spice-input.c
@@ -26,12 +26,15 @@
#include "qemu-common.h"
#include "ui/qemu-spice.h"
#include "ui/console.h"
+#include "ui/keymaps.h"
+#include "ui/input.h"
/* keyboard bits */
typedef struct QemuSpiceKbd {
SpiceKbdInstance sin;
int ledstate;
+ bool emul0;
} QemuSpiceKbd;
static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag);
@@ -47,9 +50,24 @@ static const SpiceKbdInterface kbd_interface = {
.get_leds = kbd_get_leds,
};
-static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag)
+static void kbd_push_key(SpiceKbdInstance *sin, uint8_t scancode)
{
- kbd_put_keycode(frag);
+ QemuSpiceKbd *kbd = container_of(sin, QemuSpiceKbd, sin);
+ int keycode;
+ bool up;
+
+ if (scancode == SCANCODE_EMUL0) {
+ kbd->emul0 = true;
+ return;
+ }
+ keycode = scancode & ~SCANCODE_UP;
+ up = scancode & SCANCODE_UP;
+ if (kbd->emul0) {
+ kbd->emul0 = false;
+ keycode |= SCANCODE_GREY;
+ }
+
+ qemu_input_event_send_key_number(NULL, keycode, !up);
}
static uint8_t kbd_get_leds(SpiceKbdInstance *sin)
@@ -80,41 +98,52 @@ static void kbd_leds(void *opaque, int ledstate)
typedef struct QemuSpicePointer {
SpiceMouseInstance mouse;
SpiceTabletInstance tablet;
- int width, height, x, y;
+ int width, height;
+ uint32_t last_bmask;
Notifier mouse_mode;
bool absolute;
} QemuSpicePointer;
-static int map_buttons(int spice_buttons)
+static void spice_update_buttons(QemuSpicePointer *pointer,
+ int wheel, uint32_t button_mask)
{
- int qemu_buttons = 0;
-
- /*
- * Note: SPICE_MOUSE_BUTTON_* specifies the wire protocol but this
- * isn't what we get passed in via interface callbacks for the
- * middle and right button ...
- */
- if (spice_buttons & SPICE_MOUSE_BUTTON_MASK_LEFT) {
- qemu_buttons |= MOUSE_EVENT_LBUTTON;
+ static uint32_t bmap[INPUT_BUTTON_MAX] = {
+ [INPUT_BUTTON_LEFT] = 0x01,
+ [INPUT_BUTTON_MIDDLE] = 0x04,
+ [INPUT_BUTTON_RIGHT] = 0x02,
+ [INPUT_BUTTON_WHEEL_UP] = 0x10,
+ [INPUT_BUTTON_WHEEL_DOWN] = 0x20,
+ };
+
+ if (wheel < 0) {
+ button_mask |= 0x10;
}
- if (spice_buttons & 0x04 /* SPICE_MOUSE_BUTTON_MASK_MIDDLE */) {
- qemu_buttons |= MOUSE_EVENT_MBUTTON;
+ if (wheel > 0) {
+ button_mask |= 0x20;
}
- if (spice_buttons & 0x02 /* SPICE_MOUSE_BUTTON_MASK_RIGHT */) {
- qemu_buttons |= MOUSE_EVENT_RBUTTON;
+
+ if (pointer->last_bmask == button_mask) {
+ return;
}
- return qemu_buttons;
+ qemu_input_update_buttons(NULL, bmap, pointer->last_bmask, button_mask);
+ pointer->last_bmask = button_mask;
}
static void mouse_motion(SpiceMouseInstance *sin, int dx, int dy, int dz,
uint32_t buttons_state)
{
- kbd_mouse_event(dx, dy, dz, map_buttons(buttons_state));
+ QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, mouse);
+ spice_update_buttons(pointer, dz, buttons_state);
+ qemu_input_queue_rel(NULL, INPUT_AXIS_X, dx);
+ qemu_input_queue_rel(NULL, INPUT_AXIS_Y, dy);
+ qemu_input_event_sync();
}
static void mouse_buttons(SpiceMouseInstance *sin, uint32_t buttons_state)
{
- kbd_mouse_event(0, 0, 0, map_buttons(buttons_state));
+ QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, mouse);
+ spice_update_buttons(pointer, 0, buttons_state);
+ qemu_input_event_sync();
}
static const SpiceMouseInterface mouse_interface = {
@@ -145,9 +174,10 @@ static void tablet_position(SpiceTabletInstance* sin, int x, int y,
{
QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
- pointer->x = x * 0x7FFF / (pointer->width - 1);
- pointer->y = y * 0x7FFF / (pointer->height - 1);
- kbd_mouse_event(pointer->x, pointer->y, 0, map_buttons(buttons_state));
+ spice_update_buttons(pointer, 0, buttons_state);
+ qemu_input_queue_abs(NULL, INPUT_AXIS_X, x, pointer->width);
+ qemu_input_queue_abs(NULL, INPUT_AXIS_Y, y, pointer->width);
+ qemu_input_event_sync();
}
@@ -156,7 +186,8 @@ static void tablet_wheel(SpiceTabletInstance* sin, int wheel,
{
QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
- kbd_mouse_event(pointer->x, pointer->y, wheel, map_buttons(buttons_state));
+ spice_update_buttons(pointer, wheel, buttons_state);
+ qemu_input_event_sync();
}
static void tablet_buttons(SpiceTabletInstance *sin,
@@ -164,7 +195,8 @@ static void tablet_buttons(SpiceTabletInstance *sin,
{
QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet);
- kbd_mouse_event(pointer->x, pointer->y, 0, map_buttons(buttons_state));
+ spice_update_buttons(pointer, 0, buttons_state);
+ qemu_input_event_sync();
}
static const SpiceTabletInterface tablet_interface = {
@@ -181,7 +213,7 @@ static const SpiceTabletInterface tablet_interface = {
static void mouse_mode_notifier(Notifier *notifier, void *data)
{
QemuSpicePointer *pointer = container_of(notifier, QemuSpicePointer, mouse_mode);
- bool is_absolute = kbd_mouse_is_absolute();
+ bool is_absolute = qemu_input_is_absolute();
if (pointer->absolute == is_absolute) {
return;
diff --git a/ui/vnc.c b/ui/vnc.c
index 5601cc34ef..7dfc94a358 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -33,6 +33,7 @@
#include "qapi/qmp/types.h"
#include "qmp-commands.h"
#include "qemu/osdep.h"
+#include "ui/input.h"
#define VNC_REFRESH_INTERVAL_BASE GUI_REFRESH_INTERVAL_DEFAULT
#define VNC_REFRESH_INTERVAL_INC 50
@@ -1483,7 +1484,7 @@ static void client_cut_text(VncState *vs, size_t len, uint8_t *text)
static void check_pointer_type_change(Notifier *notifier, void *data)
{
VncState *vs = container_of(notifier, VncState, mouse_mode_notifier);
- int absolute = kbd_mouse_is_absolute();
+ int absolute = qemu_input_is_absolute();
if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) {
vnc_lock_output(vs);
@@ -1502,39 +1503,37 @@ static void check_pointer_type_change(Notifier *notifier, void *data)
static void pointer_event(VncState *vs, int button_mask, int x, int y)
{
- int buttons = 0;
- int dz = 0;
+ static uint32_t bmap[INPUT_BUTTON_MAX] = {
+ [INPUT_BUTTON_LEFT] = 0x01,
+ [INPUT_BUTTON_MIDDLE] = 0x02,
+ [INPUT_BUTTON_RIGHT] = 0x04,
+ [INPUT_BUTTON_WHEEL_UP] = 0x08,
+ [INPUT_BUTTON_WHEEL_DOWN] = 0x10,
+ };
+ QemuConsole *con = vs->vd->dcl.con;
int width = surface_width(vs->vd->ds);
int height = surface_height(vs->vd->ds);
- if (button_mask & 0x01)
- buttons |= MOUSE_EVENT_LBUTTON;
- if (button_mask & 0x02)
- buttons |= MOUSE_EVENT_MBUTTON;
- if (button_mask & 0x04)
- buttons |= MOUSE_EVENT_RBUTTON;
- if (button_mask & 0x08)
- dz = -1;
- if (button_mask & 0x10)
- dz = 1;
+ if (vs->last_bmask != button_mask) {
+ qemu_input_update_buttons(con, bmap, vs->last_bmask, button_mask);
+ vs->last_bmask = button_mask;
+ }
if (vs->absolute) {
- kbd_mouse_event(width > 1 ? x * 0x7FFF / (width - 1) : 0x4000,
- height > 1 ? y * 0x7FFF / (height - 1) : 0x4000,
- dz, buttons);
+ qemu_input_queue_abs(con, INPUT_AXIS_X, x, width);
+ qemu_input_queue_abs(con, INPUT_AXIS_Y, y, height);
} else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) {
- x -= 0x7FFF;
- y -= 0x7FFF;
-
- kbd_mouse_event(x, y, dz, buttons);
+ qemu_input_queue_rel(con, INPUT_AXIS_X, x - 0x7FFF);
+ qemu_input_queue_rel(con, INPUT_AXIS_Y, y - 0x7FFF);
} else {
- if (vs->last_x != -1)
- kbd_mouse_event(x - vs->last_x,
- y - vs->last_y,
- dz, buttons);
+ if (vs->last_x != -1) {
+ qemu_input_queue_rel(con, INPUT_AXIS_X, x - vs->last_x);
+ qemu_input_queue_rel(con, INPUT_AXIS_Y, y - vs->last_y);
+ }
vs->last_x = x;
vs->last_y = y;
}
+ qemu_input_event_sync();
}
static void reset_keys(VncState *vs)
@@ -1542,9 +1541,7 @@ static void reset_keys(VncState *vs)
int i;
for(i = 0; i < 256; i++) {
if (vs->modifiers_state[i]) {
- if (i & SCANCODE_GREY)
- kbd_put_keycode(SCANCODE_EMUL0);
- kbd_put_keycode(i | SCANCODE_UP);
+ qemu_input_event_send_key_number(vs->vd->dcl.con, i, false);
vs->modifiers_state[i] = 0;
}
}
@@ -1553,12 +1550,8 @@ static void reset_keys(VncState *vs)
static void press_key(VncState *vs, int keysym)
{
int keycode = keysym2scancode(vs->vd->kbd_layout, keysym) & SCANCODE_KEYMASK;
- if (keycode & SCANCODE_GREY)
- kbd_put_keycode(SCANCODE_EMUL0);
- kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
- if (keycode & SCANCODE_GREY)
- kbd_put_keycode(SCANCODE_EMUL0);
- kbd_put_keycode(keycode | SCANCODE_UP);
+ qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, true);
+ qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false);
}
static int current_led_state(VncState *vs)
@@ -1700,12 +1693,7 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
}
if (qemu_console_is_graphic(NULL)) {
- if (keycode & SCANCODE_GREY)
- kbd_put_keycode(SCANCODE_EMUL0);
- if (down)
- kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
- else
- kbd_put_keycode(keycode | SCANCODE_UP);
+ qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, down);
} else {
bool numlock = vs->modifiers_state[0x45];
bool control = (vs->modifiers_state[0x1d] ||
@@ -1826,10 +1814,7 @@ static void vnc_release_modifiers(VncState *vs)
if (!vs->modifiers_state[keycode]) {
continue;
}
- if (keycode & SCANCODE_GREY) {
- kbd_put_keycode(SCANCODE_EMUL0);
- }
- kbd_put_keycode(keycode | SCANCODE_UP);
+ qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false);
}
}
diff --git a/ui/vnc.h b/ui/vnc.h
index 6e9921387f..e63c14284b 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -257,6 +257,7 @@ struct VncState
int absolute;
int last_x;
int last_y;
+ uint32_t last_bmask;
int client_width;
int client_height;
VncShareMode share_mode;
diff --git a/util/host-utils.c b/util/host-utils.c
index f0784d6335..ee57ef55f6 100644
--- a/util/host-utils.c
+++ b/util/host-utils.c
@@ -86,4 +86,79 @@ void muls64 (uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b)
}
*phigh = rh;
}
+
+/* Unsigned 128x64 division. Returns 1 if overflow (divide by zero or */
+/* quotient exceeds 64 bits). Otherwise returns quotient via plow and */
+/* remainder via phigh. */
+int divu128(uint64_t *plow, uint64_t *phigh, uint64_t divisor)
+{
+ uint64_t dhi = *phigh;
+ uint64_t dlo = *plow;
+ unsigned i;
+ uint64_t carry = 0;
+
+ if (divisor == 0) {
+ return 1;
+ } else if (dhi == 0) {
+ *plow = dlo / divisor;
+ *phigh = dlo % divisor;
+ return 0;
+ } else if (dhi > divisor) {
+ return 1;
+ } else {
+
+ for (i = 0; i < 64; i++) {
+ carry = dhi >> 63;
+ dhi = (dhi << 1) | (dlo >> 63);
+ if (carry || (dhi >= divisor)) {
+ dhi -= divisor;
+ carry = 1;
+ } else {
+ carry = 0;
+ }
+ dlo = (dlo << 1) | carry;
+ }
+
+ *plow = dlo;
+ *phigh = dhi;
+ return 0;
+ }
+}
+
+int divs128(int64_t *plow, int64_t *phigh, int64_t divisor)
+{
+ int sgn_dvdnd = *phigh < 0;
+ int sgn_divsr = divisor < 0;
+ int overflow = 0;
+
+ if (sgn_dvdnd) {
+ *plow = ~(*plow);
+ *phigh = ~(*phigh);
+ if (*plow == (int64_t)-1) {
+ *plow = 0;
+ (*phigh)++;
+ } else {
+ (*plow)++;
+ }
+ }
+
+ if (sgn_divsr) {
+ divisor = 0 - divisor;
+ }
+
+ overflow = divu128((uint64_t *)plow, (uint64_t *)phigh, (uint64_t)divisor);
+
+ if (sgn_dvdnd ^ sgn_divsr) {
+ *plow = 0 - *plow;
+ }
+
+ if (!overflow) {
+ if ((*plow < 0) ^ (sgn_dvdnd ^ sgn_divsr)) {
+ overflow = 1;
+ }
+ }
+
+ return overflow;
+}
+
#endif /* !CONFIG_INT128 */
diff --git a/vl.c b/vl.c
index 685a7a9f45..41581c1c23 100644
--- a/vl.c
+++ b/vl.c
@@ -374,6 +374,10 @@ static QemuOptsList qemu_machine_opts = {
.name = "firmware",
.type = QEMU_OPT_STRING,
.help = "firmware image",
+ },{
+ .name = "kvm-type",
+ .type = QEMU_OPT_STRING,
+ .help = "Specifies the KVM virtualization mode (HV, PR)",
},
{ /* End of list */ }
},
@@ -2578,7 +2582,7 @@ static QEMUMachine *machine_parse(const char *name)
exit(!name || !is_help_option(name));
}
-static int tcg_init(void)
+static int tcg_init(QEMUMachine *machine)
{
tcg_exec_init(tcg_tb_size * 1024 * 1024);
return 0;
@@ -2588,7 +2592,7 @@ static struct {
const char *opt_name;
const char *name;
int (*available)(void);
- int (*init)(void);
+ int (*init)(QEMUMachine *);
bool *allowed;
} accel_list[] = {
{ "tcg", "tcg", tcg_available, tcg_init, &tcg_allowed },
@@ -2597,7 +2601,7 @@ static struct {
{ "qtest", "QTest", qtest_available, qtest_init_accel, &qtest_allowed },
};
-static int configure_accelerator(void)
+static int configure_accelerator(QEMUMachine *machine)
{
const char *p;
char buf[10];
@@ -2624,7 +2628,7 @@ static int configure_accelerator(void)
continue;
}
*(accel_list[i].allowed) = true;
- ret = accel_list[i].init();
+ ret = accel_list[i].init(machine);
if (ret < 0) {
init_failed = true;
fprintf(stderr, "failed to initialize %s: %s\n",
@@ -4053,7 +4057,7 @@ int main(int argc, char **argv, char **envp)
exit(0);
}
- configure_accelerator();
+ configure_accelerator(machine);
if (qtest_chrdev) {
Error *local_err = NULL;
diff --git a/xen-all.c b/xen-all.c
index 4a594bdd9b..ba3473901e 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -1001,7 +1001,7 @@ static void xen_exit_notifier(Notifier *n, void *data)
xs_daemon_close(state->xenstore);
}
-int xen_init(void)
+int xen_init(QEMUMachine *machine)
{
xen_xc = xen_xc_interface_open(0, 0, 0);
if (xen_xc == XC_HANDLER_INITIAL_VALUE) {
diff --git a/xen-stub.c b/xen-stub.c
index ad189a6df8..59927cb5d6 100644
--- a/xen-stub.c
+++ b/xen-stub.c
@@ -47,7 +47,7 @@ qemu_irq *xen_interrupt_controller_init(void)
return NULL;
}
-int xen_init(void)
+int xen_init(QEMUMachine *machine)
{
return -ENOSYS;
}