Merge remote-tracking branch 'upstream/master' into main

This commit is contained in:
Andrea Fioraldi 2022-10-19 10:18:02 +02:00
commit eb8a65328d
75 changed files with 6631 additions and 3352 deletions

View File

@ -70,7 +70,9 @@ Paul Burton <paulburton@kernel.org> <paul.burton@mips.com>
Paul Burton <paulburton@kernel.org> <paul.burton@imgtec.com> Paul Burton <paulburton@kernel.org> <paul.burton@imgtec.com>
Paul Burton <paulburton@kernel.org> <paul@archlinuxmips.org> Paul Burton <paulburton@kernel.org> <paul@archlinuxmips.org>
Paul Burton <paulburton@kernel.org> <pburton@wavecomp.com> Paul Burton <paulburton@kernel.org> <pburton@wavecomp.com>
Philippe Mathieu-Daudé <f4bug@amsat.org> <philmd@redhat.com> Philippe Mathieu-Daudé <philmd@linaro.org> <f4bug@amsat.org>
Philippe Mathieu-Daudé <philmd@linaro.org> <philmd@redhat.com>
Philippe Mathieu-Daudé <philmd@linaro.org> <philmd@fungible.com>
Stefan Brankovic <stefan.brankovic@syrmia.com> <stefan.brankovic@rt-rk.com.com> Stefan Brankovic <stefan.brankovic@syrmia.com> <stefan.brankovic@rt-rk.com.com>
Yongbok Kim <yongbok.kim@mips.com> <yongbok.kim@imgtec.com> Yongbok Kim <yongbok.kim@mips.com> <yongbok.kim@imgtec.com>

View File

@ -110,7 +110,7 @@ T: git https://gitlab.com/cohuck/qemu.git s390-next
L: qemu-s390x@nongnu.org L: qemu-s390x@nongnu.org
MIPS general architecture support MIPS general architecture support
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
R: Jiaxun Yang <jiaxun.yang@flygoat.com> R: Jiaxun Yang <jiaxun.yang@flygoat.com>
S: Odd Fixes S: Odd Fixes
K: ^Subject:.*(?i)mips K: ^Subject:.*(?i)mips
@ -233,7 +233,7 @@ F: tests/docker/dockerfiles/debian-microblaze-cross.d/build-toolchain.sh
F: tests/tcg/nios2/Makefile.target F: tests/tcg/nios2/Makefile.target
MIPS TCG CPUs MIPS TCG CPUs
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
R: Aurelien Jarno <aurelien@aurel32.net> R: Aurelien Jarno <aurelien@aurel32.net>
R: Jiaxun Yang <jiaxun.yang@flygoat.com> R: Jiaxun Yang <jiaxun.yang@flygoat.com>
R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com> R: Aleksandar Rikalo <aleksandar.rikalo@syrmia.com>
@ -267,8 +267,8 @@ F: hw/openrisc/
F: tests/tcg/openrisc/ F: tests/tcg/openrisc/
PowerPC TCG CPUs PowerPC TCG CPUs
M: Cédric Le Goater <clg@kaod.org>
M: Daniel Henrique Barboza <danielhb413@gmail.com> M: Daniel Henrique Barboza <danielhb413@gmail.com>
R: Cédric Le Goater <clg@kaod.org>
R: David Gibson <david@gibson.dropbear.id.au> R: David Gibson <david@gibson.dropbear.id.au>
R: Greg Kurz <groug@kaod.org> R: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
@ -392,8 +392,8 @@ F: target/mips/kvm*
F: target/mips/sysemu/ F: target/mips/sysemu/
PPC KVM CPUs PPC KVM CPUs
M: Cédric Le Goater <clg@kaod.org>
M: Daniel Henrique Barboza <danielhb413@gmail.com> M: Daniel Henrique Barboza <danielhb413@gmail.com>
R: Cédric Le Goater <clg@kaod.org>
R: David Gibson <david@gibson.dropbear.id.au> R: David Gibson <david@gibson.dropbear.id.au>
R: Greg Kurz <groug@kaod.org> R: Greg Kurz <groug@kaod.org>
S: Maintained S: Maintained
@ -550,7 +550,7 @@ X: qga/*win32*
F: qemu.nsi F: qemu.nsi
Darwin (macOS, iOS) Darwin (macOS, iOS)
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
S: Odd Fixes S: Odd Fixes
F: .gitlab-ci.d/cirrus/macos-* F: .gitlab-ci.d/cirrus/macos-*
F: */*.m F: */*.m
@ -681,7 +681,7 @@ F: include/hw/rtc/goldfish_rtc.h
Gumstix Gumstix
M: Peter Maydell <peter.maydell@linaro.org> M: Peter Maydell <peter.maydell@linaro.org>
R: Philippe Mathieu-Daudé <f4bug@amsat.org> R: Philippe Mathieu-Daudé <philmd@linaro.org>
L: qemu-arm@nongnu.org L: qemu-arm@nongnu.org
S: Odd Fixes S: Odd Fixes
F: hw/arm/gumstix.c F: hw/arm/gumstix.c
@ -832,7 +832,7 @@ F: docs/system/arm/palm.rst
Raspberry Pi Raspberry Pi
M: Peter Maydell <peter.maydell@linaro.org> M: Peter Maydell <peter.maydell@linaro.org>
R: Philippe Mathieu-Daudé <f4bug@amsat.org> R: Philippe Mathieu-Daudé <philmd@linaro.org>
L: qemu-arm@nongnu.org L: qemu-arm@nongnu.org
S: Odd Fixes S: Odd Fixes
F: hw/arm/raspi.c F: hw/arm/raspi.c
@ -1095,7 +1095,7 @@ F: include/hw/misc/avr_power.h
F: hw/misc/avr_power.c F: hw/misc/avr_power.c
Arduino Arduino
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
S: Maintained S: Maintained
F: hw/avr/arduino.c F: hw/avr/arduino.c
@ -1210,7 +1210,7 @@ F: hw/microblaze/petalogix_ml605_mmu.c
MIPS Machines MIPS Machines
------------- -------------
Overall MIPS Machines Overall MIPS Machines
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
S: Odd Fixes S: Odd Fixes
F: configs/devices/mips*/* F: configs/devices/mips*/*
F: hw/mips/ F: hw/mips/
@ -1225,7 +1225,7 @@ F: hw/display/jazz_led.c
F: hw/dma/rc4030.c F: hw/dma/rc4030.c
Malta Malta
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
R: Aurelien Jarno <aurelien@aurel32.net> R: Aurelien Jarno <aurelien@aurel32.net>
S: Odd Fixes S: Odd Fixes
F: hw/isa/piix4.c F: hw/isa/piix4.c
@ -1244,7 +1244,7 @@ F: hw/net/mipsnet.c
Fuloong 2E Fuloong 2E
M: Huacai Chen <chenhuacai@kernel.org> M: Huacai Chen <chenhuacai@kernel.org>
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
R: Jiaxun Yang <jiaxun.yang@flygoat.com> R: Jiaxun Yang <jiaxun.yang@flygoat.com>
S: Odd Fixes S: Odd Fixes
F: hw/mips/fuloong2e.c F: hw/mips/fuloong2e.c
@ -1365,8 +1365,8 @@ F: include/hw/rtc/m48t59.h
F: tests/avocado/ppc_prep_40p.py F: tests/avocado/ppc_prep_40p.py
sPAPR (pseries) sPAPR (pseries)
M: Cédric Le Goater <clg@kaod.org>
M: Daniel Henrique Barboza <danielhb413@gmail.com> M: Daniel Henrique Barboza <danielhb413@gmail.com>
R: Cédric Le Goater <clg@kaod.org>
R: David Gibson <david@gibson.dropbear.id.au> R: David Gibson <david@gibson.dropbear.id.au>
R: Greg Kurz <groug@kaod.org> R: Greg Kurz <groug@kaod.org>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
@ -1387,7 +1387,7 @@ F: tests/avocado/ppc_pseries.py
PowerNV (Non-Virtualized) PowerNV (Non-Virtualized)
M: Cédric Le Goater <clg@kaod.org> M: Cédric Le Goater <clg@kaod.org>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Maintained S: Odd Fixes
F: docs/system/ppc/powernv.rst F: docs/system/ppc/powernv.rst
F: hw/ppc/pnv* F: hw/ppc/pnv*
F: hw/intc/pnv* F: hw/intc/pnv*
@ -1700,7 +1700,7 @@ F: pc-bios/bios-microvm.bin
Machine core Machine core
M: Eduardo Habkost <eduardo@habkost.net> M: Eduardo Habkost <eduardo@habkost.net>
M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com> M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
R: Philippe Mathieu-Daudé <f4bug@amsat.org> R: Philippe Mathieu-Daudé <philmd@linaro.org>
R: Yanan Wang <wangyanan55@huawei.com> R: Yanan Wang <wangyanan55@huawei.com>
S: Supported S: Supported
F: cpu.c F: cpu.c
@ -1893,7 +1893,7 @@ F: docs/virtio-net-failover.rst
T: git https://github.com/jasowang/qemu.git net T: git https://github.com/jasowang/qemu.git net
Parallel NOR Flash devices Parallel NOR Flash devices
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
T: git https://gitlab.com/philmd/qemu.git pflash-next T: git https://gitlab.com/philmd/qemu.git pflash-next
S: Maintained S: Maintained
F: hw/block/pflash_cfi*.c F: hw/block/pflash_cfi*.c
@ -1926,7 +1926,7 @@ S: Maintained
F: hw/ssi/xilinx_* F: hw/ssi/xilinx_*
SD (Secure Card) SD (Secure Card)
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
M: Bin Meng <bin.meng@windriver.com> M: Bin Meng <bin.meng@windriver.com>
L: qemu-block@nongnu.org L: qemu-block@nongnu.org
S: Odd Fixes S: Odd Fixes
@ -2233,14 +2233,14 @@ F: tests/qtest/vmgenid-test.c
F: stubs/vmgenid.c F: stubs/vmgenid.c
LED LED
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
S: Maintained S: Maintained
F: include/hw/misc/led.h F: include/hw/misc/led.h
F: hw/misc/led.c F: hw/misc/led.c
Unimplemented device Unimplemented device
M: Peter Maydell <peter.maydell@linaro.org> M: Peter Maydell <peter.maydell@linaro.org>
R: Philippe Mathieu-Daudé <f4bug@amsat.org> R: Philippe Mathieu-Daudé <philmd@linaro.org>
R: Ani Sinha <ani@anisinha.ca> R: Ani Sinha <ani@anisinha.ca>
S: Maintained S: Maintained
F: include/hw/misc/unimp.h F: include/hw/misc/unimp.h
@ -2248,7 +2248,7 @@ F: hw/misc/unimp.c
Empty slot Empty slot
M: Artyom Tarasenko <atar4qemu@gmail.com> M: Artyom Tarasenko <atar4qemu@gmail.com>
R: Philippe Mathieu-Daudé <f4bug@amsat.org> R: Philippe Mathieu-Daudé <philmd@linaro.org>
R: Ani Sinha <ani@anisinha.ca> R: Ani Sinha <ani@anisinha.ca>
S: Maintained S: Maintained
F: include/hw/misc/empty_slot.h F: include/hw/misc/empty_slot.h
@ -2312,13 +2312,13 @@ F: qemu-edid.c
PIIX4 South Bridge (i82371AB) PIIX4 South Bridge (i82371AB)
M: Hervé Poussineau <hpoussin@reactos.org> M: Hervé Poussineau <hpoussin@reactos.org>
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
S: Maintained S: Maintained
F: hw/isa/piix4.c F: hw/isa/piix4.c
F: include/hw/southbridge/piix.h F: include/hw/southbridge/piix.h
Firmware configuration (fw_cfg) Firmware configuration (fw_cfg)
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
R: Gerd Hoffmann <kraxel@redhat.com> R: Gerd Hoffmann <kraxel@redhat.com>
S: Supported S: Supported
F: docs/specs/fw_cfg.txt F: docs/specs/fw_cfg.txt
@ -2333,7 +2333,7 @@ T: git https://github.com/philmd/qemu.git fw_cfg-next
XIVE XIVE
M: Cédric Le Goater <clg@kaod.org> M: Cédric Le Goater <clg@kaod.org>
L: qemu-ppc@nongnu.org L: qemu-ppc@nongnu.org
S: Supported S: Odd Fixes
F: hw/*/*xive* F: hw/*/*xive*
F: include/hw/*/*xive* F: include/hw/*/*xive*
F: docs/*/*xive* F: docs/*/*xive*
@ -2374,13 +2374,13 @@ F: hw/intc/openpic.c
F: include/hw/ppc/openpic.h F: include/hw/ppc/openpic.h
MIPS CPS MIPS CPS
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
S: Odd Fixes S: Odd Fixes
F: hw/misc/mips_* F: hw/misc/mips_*
F: include/hw/misc/mips_* F: include/hw/misc/mips_*
MIPS GIC MIPS GIC
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
S: Odd Fixes S: Odd Fixes
F: hw/intc/mips_gic.c F: hw/intc/mips_gic.c
F: hw/timer/mips_gictimer.c F: hw/timer/mips_gictimer.c
@ -2462,7 +2462,7 @@ F: audio/alsaaudio.c
Core Audio framework backend Core Audio framework backend
M: Gerd Hoffmann <kraxel@redhat.com> M: Gerd Hoffmann <kraxel@redhat.com>
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
R: Christian Schoenebeck <qemu_oss@crudebyte.com> R: Christian Schoenebeck <qemu_oss@crudebyte.com>
R: Akihiko Odaki <akihiko.odaki@gmail.com> R: Akihiko Odaki <akihiko.odaki@gmail.com>
S: Odd Fixes S: Odd Fixes
@ -2687,7 +2687,7 @@ F: scripts/coccinelle/errp-guard.cocci
GDB stub GDB stub
M: Alex Bennée <alex.bennee@linaro.org> M: Alex Bennée <alex.bennee@linaro.org>
R: Philippe Mathieu-Daudé <f4bug@amsat.org> R: Philippe Mathieu-Daudé <philmd@linaro.org>
S: Maintained S: Maintained
F: gdbstub/* F: gdbstub/*
F: include/exec/gdbstub.h F: include/exec/gdbstub.h
@ -2698,7 +2698,7 @@ Memory API
M: Paolo Bonzini <pbonzini@redhat.com> M: Paolo Bonzini <pbonzini@redhat.com>
M: Peter Xu <peterx@redhat.com> M: Peter Xu <peterx@redhat.com>
M: David Hildenbrand <david@redhat.com> M: David Hildenbrand <david@redhat.com>
R: Philippe Mathieu-Daudé <f4bug@amsat.org> R: Philippe Mathieu-Daudé <philmd@linaro.org>
S: Supported S: Supported
F: include/exec/ioport.h F: include/exec/ioport.h
F: include/exec/memop.h F: include/exec/memop.h
@ -2748,7 +2748,7 @@ F: util/drm.c
Cocoa graphics Cocoa graphics
M: Peter Maydell <peter.maydell@linaro.org> M: Peter Maydell <peter.maydell@linaro.org>
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
R: Akihiko Odaki <akihiko.odaki@gmail.com> R: Akihiko Odaki <akihiko.odaki@gmail.com>
S: Odd Fixes S: Odd Fixes
F: ui/cocoa.m F: ui/cocoa.m
@ -3231,14 +3231,14 @@ F: tests/qtest/max34451-test.c
F: tests/qtest/isl_pmbus_vr-test.c F: tests/qtest/isl_pmbus_vr-test.c
Firmware schema specifications Firmware schema specifications
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
R: Daniel P. Berrange <berrange@redhat.com> R: Daniel P. Berrange <berrange@redhat.com>
R: Kashyap Chamarthy <kchamart@redhat.com> R: Kashyap Chamarthy <kchamart@redhat.com>
S: Maintained S: Maintained
F: docs/interop/firmware.json F: docs/interop/firmware.json
EDK2 Firmware EDK2 Firmware
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
M: Gerd Hoffmann <kraxel@redhat.com> M: Gerd Hoffmann <kraxel@redhat.com>
S: Supported S: Supported
F: hw/i386/*ovmf* F: hw/i386/*ovmf*
@ -3349,7 +3349,7 @@ S: Maintained
F: tcg/loongarch64/ F: tcg/loongarch64/
MIPS TCG target MIPS TCG target
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
R: Aurelien Jarno <aurelien@aurel32.net> R: Aurelien Jarno <aurelien@aurel32.net>
R: Huacai Chen <chenhuacai@kernel.org> R: Huacai Chen <chenhuacai@kernel.org>
R: Jiaxun Yang <jiaxun.yang@flygoat.com> R: Jiaxun Yang <jiaxun.yang@flygoat.com>
@ -3472,7 +3472,7 @@ F: block/null.c
NVMe Block Driver NVMe Block Driver
M: Stefan Hajnoczi <stefanha@redhat.com> M: Stefan Hajnoczi <stefanha@redhat.com>
R: Fam Zheng <fam@euphon.net> R: Fam Zheng <fam@euphon.net>
R: Philippe Mathieu-Daudé <f4bug@amsat.org> R: Philippe Mathieu-Daudé <philmd@linaro.org>
L: qemu-block@nongnu.org L: qemu-block@nongnu.org
S: Supported S: Supported
F: block/nvme* F: block/nvme*
@ -3691,7 +3691,7 @@ Build and test automation
------------------------- -------------------------
Build and test automation, general continuous integration Build and test automation, general continuous integration
M: Alex Bennée <alex.bennee@linaro.org> M: Alex Bennée <alex.bennee@linaro.org>
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
M: Thomas Huth <thuth@redhat.com> M: Thomas Huth <thuth@redhat.com>
R: Wainer dos Santos Moschetta <wainersm@redhat.com> R: Wainer dos Santos Moschetta <wainersm@redhat.com>
R: Beraldo Leal <bleal@redhat.com> R: Beraldo Leal <bleal@redhat.com>
@ -3724,7 +3724,7 @@ W: https://cirrus-ci.com/github/qemu/qemu
Guest Test Compilation Support Guest Test Compilation Support
M: Alex Bennée <alex.bennee@linaro.org> M: Alex Bennée <alex.bennee@linaro.org>
R: Philippe Mathieu-Daudé <f4bug@amsat.org> R: Philippe Mathieu-Daudé <philmd@linaro.org>
S: Maintained S: Maintained
F: tests/tcg/Makefile F: tests/tcg/Makefile
F: tests/tcg/Makefile.include F: tests/tcg/Makefile.include
@ -3732,7 +3732,7 @@ F: tests/tcg/Makefile.include
Integration Testing with the Avocado framework Integration Testing with the Avocado framework
W: https://trello.com/b/6Qi1pxVn/avocado-qemu W: https://trello.com/b/6Qi1pxVn/avocado-qemu
R: Cleber Rosa <crosa@redhat.com> R: Cleber Rosa <crosa@redhat.com>
R: Philippe Mathieu-Daudé <f4bug@amsat.org> R: Philippe Mathieu-Daudé <philmd@linaro.org>
R: Wainer dos Santos Moschetta <wainersm@redhat.com> R: Wainer dos Santos Moschetta <wainersm@redhat.com>
R: Beraldo Leal <bleal@redhat.com> R: Beraldo Leal <bleal@redhat.com>
S: Odd Fixes S: Odd Fixes
@ -3740,7 +3740,7 @@ F: tests/avocado/
GitLab custom runner (Works On Arm Sponsored) GitLab custom runner (Works On Arm Sponsored)
M: Alex Bennée <alex.bennee@linaro.org> M: Alex Bennée <alex.bennee@linaro.org>
M: Philippe Mathieu-Daudé <f4bug@amsat.org> M: Philippe Mathieu-Daudé <philmd@linaro.org>
S: Maintained S: Maintained
F: .gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml F: .gitlab-ci.d/custom-runners/ubuntu-22.04-aarch64.yml
F: .gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml F: .gitlab-ci.d/custom-runners/ubuntu-22.04-aarch32.yml

View File

@ -1,7 +1,8 @@
# Default configuration for ppc-softmmu # Default configuration for ppc-softmmu
# For embedded PPCs: # For embedded PPCs:
CONFIG_E500=y CONFIG_E500PLAT=y
CONFIG_MPC8544DS=y
CONFIG_PPC405=y CONFIG_PPC405=y
CONFIG_PPC440=y CONFIG_PPC440=y
CONFIG_VIRTEX=y CONFIG_VIRTEX=y

51
configure vendored
View File

@ -1455,30 +1455,31 @@ if test "$tcg" = "enabled"; then
git_submodules="$git_submodules tests/fp/berkeley-softfloat-3" git_submodules="$git_submodules tests/fp/berkeley-softfloat-3"
fi fi
# --- ##########################################
# big/little endian test # big/little endian test
cat > $TMPC << EOF cat > $TMPC << EOF
#include <stdio.h> #if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
short big_endian[] = { 0x4269, 0x4765, 0x4e64, 0x4961, 0x4e00, 0, }; # error LITTLE
short little_endian[] = { 0x694c, 0x7454, 0x654c, 0x6e45, 0x6944, 0x6e41, 0, }; #endif
int main(int argc, char *argv[]) int main(void) { return 0; }
{
return printf("%s %s\n", (char *)big_endian, (char *)little_endian);
}
EOF EOF
if compile_prog ; then if ! compile_prog ; then
if strings -a $TMPE | grep -q BiGeNdIaN ; then
bigendian="yes"
elif strings -a $TMPE | grep -q LiTtLeEnDiAn ; then
bigendian="no" bigendian="no"
else
cat > $TMPC << EOF
#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# error BIG
#endif
int main(void) { return 0; }
EOF
if ! compile_prog ; then
bigendian="yes"
else else
echo big/little test failed echo big/little test failed
exit 1 exit 1
fi fi
else
echo big/little test failed
exit 1
fi fi
########################################## ##########################################
@ -1873,6 +1874,16 @@ compute_target_variable() {
fi fi
} }
have_target() {
for i; do
case " $target_list " in
*" $i "*) return 0;;
*) ;;
esac
done
return 1
}
# probe_target_compiler TARGET # probe_target_compiler TARGET
# #
# Look for a compiler for the given target, either native or cross. # Look for a compiler for the given target, either native or cross.
@ -2293,8 +2304,9 @@ echo "# Automatically generated by configure - do not modify" > Makefile.prereqs
# Mac OS X ships with a broken assembler # Mac OS X ships with a broken assembler
roms= roms=
if test "$targetos" != "darwin" && test "$targetos" != "sunos" && \ if have_target i386-softmmu x86_64-softmmu && \
test "$targetos" != "haiku" && test "$softmmu" = yes && \ test "$targetos" != "darwin" && test "$targetos" != "sunos" && \
test "$targetos" != "haiku" && \
probe_target_compiler i386-softmmu; then probe_target_compiler i386-softmmu; then
roms="pc-bios/optionrom" roms="pc-bios/optionrom"
config_mak=pc-bios/optionrom/config.mak config_mak=pc-bios/optionrom/config.mak
@ -2303,7 +2315,8 @@ if test "$targetos" != "darwin" && test "$targetos" != "sunos" && \
write_target_makefile >> $config_mak write_target_makefile >> $config_mak
fi fi
if test "$softmmu" = yes && probe_target_compiler ppc-softmmu; then if have_target ppc-softmmu ppc64-softmmu && \
probe_target_compiler ppc-softmmu; then
roms="$roms pc-bios/vof" roms="$roms pc-bios/vof"
config_mak=pc-bios/vof/config.mak config_mak=pc-bios/vof/config.mak
echo "# Automatically generated by configure - do not modify" > $config_mak echo "# Automatically generated by configure - do not modify" > $config_mak
@ -2313,7 +2326,7 @@ fi
# Only build s390-ccw bios if the compiler has -march=z900 or -march=z10 # Only build s390-ccw bios if the compiler has -march=z900 or -march=z10
# (which is the lowest architecture level that Clang supports) # (which is the lowest architecture level that Clang supports)
if test "$softmmu" = yes && probe_target_compiler s390x-softmmu; then if have_target s390x-softmmu && probe_target_compiler s390x-softmmu; then
write_c_skeleton write_c_skeleton
do_compiler "$target_cc" $target_cc_cflags -march=z900 -o $TMPO -c $TMPC do_compiler "$target_cc" $target_cc_cflags -march=z900 -o $TMPO -c $TMPC
has_z900=$? has_z900=$?

View File

@ -146,6 +146,9 @@ You can specify a real world SoC device that QEMU has built-in support but all
these SoCs are e500v2 based MPC85xx series, hence you cannot test anything these SoCs are e500v2 based MPC85xx series, hence you cannot test anything
built for P4080 (e500mc), P5020 (e5500) and T2080 (e6500). built for P4080 (e500mc), P5020 (e5500) and T2080 (e6500).
Networking
----------
By default a VirtIO standard PCI networking device is connected as an ethernet By default a VirtIO standard PCI networking device is connected as an ethernet
interface at PCI address 0.1.0, but we can switch that to an e1000 NIC by: interface at PCI address 0.1.0, but we can switch that to an e1000 NIC by:

View File

@ -1436,6 +1436,7 @@ static void partsN(log2)(FloatPartsN *a, float_status *s, const FloatFmt *fmt)
parts_return_nan(a, s); parts_return_nan(a, s);
return; return;
case float_class_zero: case float_class_zero:
float_raise(float_flag_divbyzero, s);
/* log2(0) = -inf */ /* log2(0) = -inf */
a->cls = float_class_inf; a->cls = float_class_inf;
a->sign = 1; a->sign = 1;

View File

@ -1800,3 +1800,18 @@ ERST
.sub_table = hmp_info_cmds, .sub_table = hmp_info_cmds,
.flags = "p", .flags = "p",
}, },
#if defined(CONFIG_FDT)
{
.name = "dumpdtb",
.args_type = "filename:F",
.params = "filename",
.help = "dump the FDT in dtb format to 'filename'",
.cmd = hmp_dumpdtb,
},
SRST
``dumpdtb`` *filename*
Dump the FDT in dtb format to *filename*.
ERST
#endif

View File

@ -8,6 +8,9 @@ config PL061
config GPIO_KEY config GPIO_KEY
bool bool
config GPIO_MPC8XXX
bool
config GPIO_PWR config GPIO_PWR
bool bool

View File

@ -1,5 +1,5 @@
softmmu_ss.add(when: 'CONFIG_E500', if_true: files('mpc8xxx.c'))
softmmu_ss.add(when: 'CONFIG_GPIO_KEY', if_true: files('gpio_key.c')) softmmu_ss.add(when: 'CONFIG_GPIO_KEY', if_true: files('gpio_key.c'))
softmmu_ss.add(when: 'CONFIG_GPIO_MPC8XXX', if_true: files('mpc8xxx.c'))
softmmu_ss.add(when: 'CONFIG_GPIO_PWR', if_true: files('gpio_pwr.c')) softmmu_ss.add(when: 'CONFIG_GPIO_PWR', if_true: files('gpio_pwr.c'))
softmmu_ss.add(when: 'CONFIG_MAX7310', if_true: files('max7310.c')) softmmu_ss.add(when: 'CONFIG_MAX7310', if_true: files('max7310.c'))
softmmu_ss.add(when: 'CONFIG_PL061', if_true: files('pl061.c')) softmmu_ss.add(when: 'CONFIG_PL061', if_true: files('pl061.c'))

View File

@ -485,9 +485,7 @@ static void microvm_machine_reset(MachineState *machine)
CPU_FOREACH(cs) { CPU_FOREACH(cs) {
cpu = X86_CPU(cs); cpu = X86_CPU(cs);
if (cpu->apic_state) { x86_cpu_after_reset(cpu);
device_legacy_reset(cpu->apic_state);
}
} }
} }

View File

@ -92,6 +92,7 @@
#include "hw/virtio/virtio-mem-pci.h" #include "hw/virtio/virtio-mem-pci.h"
#include "hw/mem/memory-device.h" #include "hw/mem/memory-device.h"
#include "sysemu/replay.h" #include "sysemu/replay.h"
#include "target/i386/cpu.h"
#include "qapi/qmp/qerror.h" #include "qapi/qmp/qerror.h"
#include "e820_memory_layout.h" #include "e820_memory_layout.h"
#include "fw_cfg.h" #include "fw_cfg.h"
@ -1859,9 +1860,7 @@ static void pc_machine_reset(MachineState *machine)
CPU_FOREACH(cs) { CPU_FOREACH(cs) {
cpu = X86_CPU(cs); cpu = X86_CPU(cs);
if (cpu->apic_state) { x86_cpu_after_reset(cpu);
device_legacy_reset(cpu->apic_state);
}
} }
} }

View File

@ -88,7 +88,6 @@ static void ipi_send(uint64_t val)
cs = qemu_get_cpu(cpuid); cs = qemu_get_cpu(cpuid);
cpu = LOONGARCH_CPU(cs); cpu = LOONGARCH_CPU(cs);
env = &cpu->env; env = &cpu->env;
loongarch_cpu_set_irq(cpu, IRQ_IPI, 1);
address_space_stl(&env->address_space_iocsr, 0x1008, address_space_stl(&env->address_space_iocsr, 0x1008,
data, MEMTXATTRS_UNSPECIFIED, NULL); data, MEMTXATTRS_UNSPECIFIED, NULL);

View File

@ -43,6 +43,8 @@
#include "boot.h" #include "boot.h"
#include <libfdt.h>
#define NIOS2_MAGIC 0x534f494e #define NIOS2_MAGIC 0x534f494e
static struct nios2_boot_info { static struct nios2_boot_info {
@ -81,6 +83,7 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
static int nios2_load_dtb(struct nios2_boot_info bi, const uint32_t ramsize, static int nios2_load_dtb(struct nios2_boot_info bi, const uint32_t ramsize,
const char *kernel_cmdline, const char *dtb_filename) const char *kernel_cmdline, const char *dtb_filename)
{ {
MachineState *machine = MACHINE(qdev_get_machine());
int fdt_size; int fdt_size;
void *fdt = NULL; void *fdt = NULL;
int r; int r;
@ -113,7 +116,10 @@ static int nios2_load_dtb(struct nios2_boot_info bi, const uint32_t ramsize,
} }
cpu_physical_memory_write(bi.fdt, fdt, fdt_size); cpu_physical_memory_write(bi.fdt, fdt, fdt_size);
g_free(fdt);
/* Set machine->fdt for 'dumpdtb' QMP/HMP command */
machine->fdt = fdt;
return fdt_size; return fdt_size;
} }

View File

@ -1,5 +1,5 @@
nios2_ss = ss.source_set() nios2_ss = ss.source_set()
nios2_ss.add(files('boot.c')) nios2_ss.add(files('boot.c'), fdt)
nios2_ss.add(when: 'CONFIG_NIOS2_10M50', if_true: files('10m50_devboard.c')) nios2_ss.add(when: 'CONFIG_NIOS2_10M50', if_true: files('10m50_devboard.c'))
nios2_ss.add(when: 'CONFIG_NIOS2_GENERIC_NOMMU', if_true: files('generic_nommu.c')) nios2_ss.add(when: 'CONFIG_NIOS2_GENERIC_NOMMU', if_true: files('generic_nommu.c'))

View File

@ -124,6 +124,7 @@ config E500
imply AT24C imply AT24C
imply VIRTIO_PCI imply VIRTIO_PCI
select ETSEC select ETSEC
select GPIO_MPC8XXX
select OPENPIC select OPENPIC
select PLATFORM_BUS select PLATFORM_BUS
select PPCE500_PCI select PPCE500_PCI
@ -132,6 +133,14 @@ config E500
select FDT_PPC select FDT_PPC
select DS1338 select DS1338
config E500PLAT
bool
select E500
config MPC8544DS
bool
select E500
config VIRTEX config VIRTEX
bool bool
select PPC4XX select PPC4XX

View File

@ -1007,7 +1007,6 @@ void ppce500_init(MachineState *machine)
} }
/* Platform Bus Device */ /* Platform Bus Device */
if (pmc->has_platform_bus) {
dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE); dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE);
dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE); dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE);
qdev_prop_set_uint32(dev, "num_irqs", pmc->platform_bus_num_irqs); qdev_prop_set_uint32(dev, "num_irqs", pmc->platform_bus_num_irqs);
@ -1023,8 +1022,7 @@ void ppce500_init(MachineState *machine)
memory_region_add_subregion(address_space_mem, memory_region_add_subregion(address_space_mem,
pmc->platform_bus_base, pmc->platform_bus_base,
sysbus_mmio_get_region(s, 0)); &pms->pbus_dev->mmio);
}
/* /*
* Smart firmware defaults ahead! * Smart firmware defaults ahead!

View File

@ -27,7 +27,6 @@ struct PPCE500MachineClass {
int mpic_version; int mpic_version;
bool has_mpc8xxx_gpio; bool has_mpc8xxx_gpio;
bool has_platform_bus;
hwaddr platform_bus_base; hwaddr platform_bus_base;
hwaddr platform_bus_size; hwaddr platform_bus_size;
int platform_bus_first_irq; int platform_bus_first_irq;

View File

@ -86,7 +86,6 @@ static void e500plat_machine_class_init(ObjectClass *oc, void *data)
pmc->fixup_devtree = e500plat_fixup_devtree; pmc->fixup_devtree = e500plat_fixup_devtree;
pmc->mpic_version = OPENPIC_MODEL_FSL_MPIC_42; pmc->mpic_version = OPENPIC_MODEL_FSL_MPIC_42;
pmc->has_mpc8xxx_gpio = true; pmc->has_mpc8xxx_gpio = true;
pmc->has_platform_bus = true;
pmc->platform_bus_base = 0xf00000000ULL; pmc->platform_bus_base = 0xf00000000ULL;
pmc->platform_bus_size = 128 * MiB; pmc->platform_bus_size = 128 * MiB;
pmc->platform_bus_first_irq = 5; pmc->platform_bus_first_irq = 5;

View File

@ -71,12 +71,10 @@ ppc_ss.add(when: 'CONFIG_MAC_OLDWORLD', if_true: files('mac_oldworld.c'))
# NewWorld PowerMac # NewWorld PowerMac
ppc_ss.add(when: 'CONFIG_MAC_NEWWORLD', if_true: files('mac_newworld.c')) ppc_ss.add(when: 'CONFIG_MAC_NEWWORLD', if_true: files('mac_newworld.c'))
# e500 # e500
ppc_ss.add(when: 'CONFIG_E500PLAT', if_true: files('e500plat.c'))
ppc_ss.add(when: 'CONFIG_MPC8544DS', if_true: files('mpc8544ds.c'))
ppc_ss.add(when: 'CONFIG_E500', if_true: files( ppc_ss.add(when: 'CONFIG_E500', if_true: files(
'e500.c', 'e500.c',
'mpc8544ds.c',
'e500plat.c'
))
ppc_ss.add(when: 'CONFIG_E500', if_true: files(
'mpc8544_guts.c', 'mpc8544_guts.c',
'ppce500_spin.c' 'ppce500_spin.c'
)) ))

View File

@ -14,6 +14,7 @@
#include "sysemu/device_tree.h" #include "sysemu/device_tree.h"
#include "hw/ppc/openpic.h" #include "hw/ppc/openpic.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qemu/units.h"
#include "cpu.h" #include "cpu.h"
static void mpc8544ds_fixup_devtree(void *fdt) static void mpc8544ds_fixup_devtree(void *fdt)
@ -36,7 +37,7 @@ static void mpc8544ds_init(MachineState *machine)
ppce500_init(machine); ppce500_init(machine);
} }
static void e500plat_machine_class_init(ObjectClass *oc, void *data) static void mpc8544ds_machine_class_init(ObjectClass *oc, void *data)
{ {
MachineClass *mc = MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc);
PPCE500MachineClass *pmc = PPCE500_MACHINE_CLASS(oc); PPCE500MachineClass *pmc = PPCE500_MACHINE_CLASS(oc);
@ -45,6 +46,10 @@ static void e500plat_machine_class_init(ObjectClass *oc, void *data)
pmc->pci_nr_slots = 2; pmc->pci_nr_slots = 2;
pmc->fixup_devtree = mpc8544ds_fixup_devtree; pmc->fixup_devtree = mpc8544ds_fixup_devtree;
pmc->mpic_version = OPENPIC_MODEL_FSL_MPIC_20; pmc->mpic_version = OPENPIC_MODEL_FSL_MPIC_20;
pmc->platform_bus_base = 0xFF800000ULL;
pmc->platform_bus_size = 8 * MiB;
pmc->platform_bus_first_irq = 5;
pmc->platform_bus_num_irqs = 10;
pmc->ccsrbar_base = 0xE0000000ULL; pmc->ccsrbar_base = 0xE0000000ULL;
pmc->pci_mmio_base = 0xC0000000ULL; pmc->pci_mmio_base = 0xC0000000ULL;
pmc->pci_mmio_bus_base = 0xC0000000ULL; pmc->pci_mmio_bus_base = 0xC0000000ULL;
@ -63,7 +68,7 @@ static void e500plat_machine_class_init(ObjectClass *oc, void *data)
static const TypeInfo mpc8544ds_info = { static const TypeInfo mpc8544ds_info = {
.name = TYPE_MPC8544DS_MACHINE, .name = TYPE_MPC8544DS_MACHINE,
.parent = TYPE_PPCE500_MACHINE, .parent = TYPE_PPCE500_MACHINE,
.class_init = e500plat_machine_class_init, .class_init = mpc8544ds_machine_class_init,
}; };
static void mpc8544ds_register_types(void) static void mpc8544ds_register_types(void)

View File

@ -331,6 +331,10 @@ static void pegasos2_machine_reset(MachineState *machine)
vof_build_dt(fdt, pm->vof); vof_build_dt(fdt, pm->vof);
vof_client_open_store(fdt, pm->vof, "/chosen", "stdout", "/failsafe"); vof_client_open_store(fdt, pm->vof, "/chosen", "stdout", "/failsafe");
/* Set machine->fdt for 'dumpdtb' QMP/HMP command */
machine->fdt = fdt;
pm->cpu->vhyp = PPC_VIRTUAL_HYPERVISOR(machine); pm->cpu->vhyp = PPC_VIRTUAL_HYPERVISOR(machine);
} }

View File

@ -678,7 +678,13 @@ static void pnv_reset(MachineState *machine)
qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt)); qemu_fdt_dumpdtb(fdt, fdt_totalsize(fdt));
cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt)); cpu_physical_memory_write(PNV_FDT_ADDR, fdt, fdt_totalsize(fdt));
g_free(fdt); /*
* Set machine->fdt for 'dumpdtb' QMP/HMP command. Free
* the existing machine->fdt to avoid leaking it during
* a reset.
*/
g_free(machine->fdt);
machine->fdt = fdt;
} }
static ISABus *pnv_chip_power8_isa_create(PnvChip *chip, Error **errp) static ISABus *pnv_chip_power8_isa_create(PnvChip *chip, Error **errp)

View File

@ -167,13 +167,6 @@ struct Ppc405SoCState {
DeviceState parent_obj; DeviceState parent_obj;
/* Public */ /* Public */
MemoryRegion ram_banks[2];
hwaddr ram_bases[2], ram_sizes[2];
bool do_dram_init;
MemoryRegion *dram_mr;
hwaddr ram_size;
PowerPCCPU cpu; PowerPCCPU cpu;
PPCUIC uic; PPCUIC uic;
Ppc405CpcState cpc; Ppc405CpcState cpc;
@ -187,6 +180,7 @@ struct Ppc405SoCState {
Ppc405PobState pob; Ppc405PobState pob;
Ppc4xxPlbState plb; Ppc4xxPlbState plb;
Ppc4xxMalState mal; Ppc4xxMalState mal;
Ppc4xxSdramDdrState sdram;
}; };
#endif /* PPC405_H */ #endif /* PPC405_H */

View File

@ -271,25 +271,13 @@ static void boot_from_kernel(MachineState *machine, PowerPCCPU *cpu)
static void ppc405_init(MachineState *machine) static void ppc405_init(MachineState *machine)
{ {
Ppc405MachineState *ppc405 = PPC405_MACHINE(machine); Ppc405MachineState *ppc405 = PPC405_MACHINE(machine);
MachineClass *mc = MACHINE_GET_CLASS(machine);
const char *kernel_filename = machine->kernel_filename; const char *kernel_filename = machine->kernel_filename;
MemoryRegion *sysmem = get_system_memory(); MemoryRegion *sysmem = get_system_memory();
if (machine->ram_size != mc->default_ram_size) {
char *sz = size_to_str(mc->default_ram_size);
error_report("Invalid RAM size, should be %s", sz);
g_free(sz);
exit(EXIT_FAILURE);
}
object_initialize_child(OBJECT(machine), "soc", &ppc405->soc, object_initialize_child(OBJECT(machine), "soc", &ppc405->soc,
TYPE_PPC405_SOC); TYPE_PPC405_SOC);
object_property_set_uint(OBJECT(&ppc405->soc), "ram-size",
machine->ram_size, &error_fatal);
object_property_set_link(OBJECT(&ppc405->soc), "dram", object_property_set_link(OBJECT(&ppc405->soc), "dram",
OBJECT(machine->ram), &error_abort); OBJECT(machine->ram), &error_abort);
object_property_set_bool(OBJECT(&ppc405->soc), "dram-init",
kernel_filename != NULL, &error_abort);
object_property_set_uint(OBJECT(&ppc405->soc), "sys-clk", 33333333, object_property_set_uint(OBJECT(&ppc405->soc), "sys-clk", 33333333,
&error_abort); &error_abort);
qdev_realize(DEVICE(&ppc405->soc), NULL, &error_fatal); qdev_realize(DEVICE(&ppc405->soc), NULL, &error_fatal);
@ -349,6 +337,7 @@ static void ppc405_init(MachineState *machine)
/* Load ELF kernel and rootfs.cpio */ /* Load ELF kernel and rootfs.cpio */
} else if (kernel_filename && !machine->firmware) { } else if (kernel_filename && !machine->firmware) {
ppc4xx_sdram_ddr_enable(&ppc405->soc.sdram);
boot_from_kernel(machine, &ppc405->soc.cpu); boot_from_kernel(machine, &ppc405->soc.cpu);
} }
} }

View File

@ -1016,6 +1016,9 @@ static void ppc405_soc_instance_init(Object *obj)
object_initialize_child(obj, "plb", &s->plb, TYPE_PPC4xx_PLB); object_initialize_child(obj, "plb", &s->plb, TYPE_PPC4xx_PLB);
object_initialize_child(obj, "mal", &s->mal, TYPE_PPC4xx_MAL); object_initialize_child(obj, "mal", &s->mal, TYPE_PPC4xx_MAL);
object_initialize_child(obj, "sdram", &s->sdram, TYPE_PPC4xx_SDRAM_DDR);
object_property_add_alias(obj, "dram", OBJECT(&s->sdram), "dram");
} }
static void ppc405_reset(void *opaque) static void ppc405_reset(void *opaque)
@ -1073,16 +1076,17 @@ static void ppc405_soc_realize(DeviceState *dev, Error **errp)
qdev_get_gpio_in(DEVICE(&s->cpu), PPC40x_INPUT_CINT)); qdev_get_gpio_in(DEVICE(&s->cpu), PPC40x_INPUT_CINT));
/* SDRAM controller */ /* SDRAM controller */
/*
* We use the 440 DDR SDRAM controller which has more regs and features
* but it's compatible enough for now
*/
object_property_set_int(OBJECT(&s->sdram), "nbanks", 2, &error_abort);
if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->sdram), &s->cpu, errp)) {
return;
}
/* XXX 405EP has no ECC interrupt */ /* XXX 405EP has no ECC interrupt */
s->ram_bases[0] = 0; sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdram), 0,
s->ram_sizes[0] = s->ram_size; qdev_get_gpio_in(DEVICE(&s->uic), 17));
memory_region_init_alias(&s->ram_banks[0], OBJECT(s),
"ppc405.sdram0", s->dram_mr,
s->ram_bases[0], s->ram_sizes[0]);
ppc4xx_sdram_init(env, qdev_get_gpio_in(DEVICE(&s->uic), 17), 1,
s->ram_banks, s->ram_bases, s->ram_sizes,
s->do_dram_init);
/* External bus controller */ /* External bus controller */
if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->ebc), &s->cpu, errp)) { if (!ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(&s->ebc), &s->cpu, errp)) {
@ -1157,14 +1161,6 @@ static void ppc405_soc_realize(DeviceState *dev, Error **errp)
/* Uses UIC IRQs 9, 15, 17 */ /* Uses UIC IRQs 9, 15, 17 */
} }
static Property ppc405_soc_properties[] = {
DEFINE_PROP_LINK("dram", Ppc405SoCState, dram_mr, TYPE_MEMORY_REGION,
MemoryRegion *),
DEFINE_PROP_BOOL("dram-init", Ppc405SoCState, do_dram_init, 0),
DEFINE_PROP_UINT64("ram-size", Ppc405SoCState, ram_size, 0),
DEFINE_PROP_END_OF_LIST(),
};
static void ppc405_soc_class_init(ObjectClass *oc, void *data) static void ppc405_soc_class_init(ObjectClass *oc, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc);
@ -1172,7 +1168,6 @@ static void ppc405_soc_class_init(ObjectClass *oc, void *data)
dc->realize = ppc405_soc_realize; dc->realize = ppc405_soc_realize;
/* Reason: only works as part of a ppc405 board/machine */ /* Reason: only works as part of a ppc405 board/machine */
dc->user_creatable = false; dc->user_creatable = false;
device_class_set_props(dc, ppc405_soc_properties);
} }
static const TypeInfo ppc405_types[] = { static const TypeInfo ppc405_types[] = {

View File

@ -16,10 +16,6 @@
void ppc4xx_l2sram_init(CPUPPCState *env); void ppc4xx_l2sram_init(CPUPPCState *env);
void ppc4xx_cpr_init(CPUPPCState *env); void ppc4xx_cpr_init(CPUPPCState *env);
void ppc4xx_sdr_init(CPUPPCState *env); void ppc4xx_sdr_init(CPUPPCState *env);
void ppc440_sdram_init(CPUPPCState *env, int nbanks,
MemoryRegion *ram_memories,
hwaddr *ram_bases, hwaddr *ram_sizes,
int do_init);
void ppc4xx_ahb_init(CPUPPCState *env); void ppc4xx_ahb_init(CPUPPCState *env);
void ppc4xx_dma_init(CPUPPCState *env, int dcr_base); void ppc4xx_dma_init(CPUPPCState *env, int dcr_base);
void ppc460ex_pcie_init(CPUPPCState *env); void ppc460ex_pcie_init(CPUPPCState *env);

View File

@ -34,6 +34,8 @@
#include "hw/qdev-properties.h" #include "hw/qdev-properties.h"
#include "qapi/error.h" #include "qapi/error.h"
#include <libfdt.h>
#define BINARY_DEVICE_TREE_FILE "bamboo.dtb" #define BINARY_DEVICE_TREE_FILE "bamboo.dtb"
/* from u-boot */ /* from u-boot */
@ -48,22 +50,15 @@
#define PPC440EP_PCI_IO 0xe8000000 #define PPC440EP_PCI_IO 0xe8000000
#define PPC440EP_PCI_IOLEN 0x00010000 #define PPC440EP_PCI_IOLEN 0x00010000
#define PPC440EP_SDRAM_NR_BANKS 4
static const ram_addr_t ppc440ep_sdram_bank_sizes[] = {
256 * MiB, 128 * MiB, 64 * MiB, 32 * MiB, 16 * MiB, 8 * MiB, 0
};
static hwaddr entry; static hwaddr entry;
static int bamboo_load_device_tree(hwaddr addr, static int bamboo_load_device_tree(MachineState *machine,
uint32_t ramsize, hwaddr addr,
hwaddr initrd_base, hwaddr initrd_base,
hwaddr initrd_size, hwaddr initrd_size)
const char *kernel_cmdline)
{ {
int ret = -1; int ret = -1;
uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(ramsize) }; uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(machine->ram_size) };
char *filename; char *filename;
int fdt_size; int fdt_size;
void *fdt; void *fdt;
@ -98,7 +93,7 @@ static int bamboo_load_device_tree(hwaddr addr,
fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n"); fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
} }
ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
kernel_cmdline); machine->kernel_cmdline);
if (ret < 0) { if (ret < 0) {
fprintf(stderr, "couldn't set /chosen/bootargs\n"); fprintf(stderr, "couldn't set /chosen/bootargs\n");
} }
@ -119,7 +114,10 @@ static int bamboo_load_device_tree(hwaddr addr,
tb_freq); tb_freq);
rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
g_free(fdt);
/* Set ms->fdt for 'dumpdtb' QMP/HMP command */
machine->fdt = fdt;
return 0; return 0;
} }
@ -163,14 +161,10 @@ static void main_cpu_reset(void *opaque)
static void bamboo_init(MachineState *machine) static void bamboo_init(MachineState *machine)
{ {
const char *kernel_filename = machine->kernel_filename; const char *kernel_filename = machine->kernel_filename;
const char *kernel_cmdline = machine->kernel_cmdline;
const char *initrd_filename = machine->initrd_filename; const char *initrd_filename = machine->initrd_filename;
unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 }; unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 };
MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *isa = g_new(MemoryRegion, 1); MemoryRegion *isa = g_new(MemoryRegion, 1);
MemoryRegion *ram_memories = g_new(MemoryRegion, PPC440EP_SDRAM_NR_BANKS);
hwaddr ram_bases[PPC440EP_SDRAM_NR_BANKS];
hwaddr ram_sizes[PPC440EP_SDRAM_NR_BANKS];
PCIBus *pcibus; PCIBus *pcibus;
PowerPCCPU *cpu; PowerPCCPU *cpu;
CPUPPCState *env; CPUPPCState *env;
@ -205,15 +199,15 @@ static void bamboo_init(MachineState *machine)
qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_CINT)); qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_CINT));
/* SDRAM controller */ /* SDRAM controller */
memset(ram_bases, 0, sizeof(ram_bases)); dev = qdev_new(TYPE_PPC4xx_SDRAM_DDR);
memset(ram_sizes, 0, sizeof(ram_sizes)); object_property_set_link(OBJECT(dev), "dram", OBJECT(machine->ram),
ppc4xx_sdram_banks(machine->ram, PPC440EP_SDRAM_NR_BANKS, ram_memories, &error_abort);
ram_bases, ram_sizes, ppc440ep_sdram_bank_sizes); ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(dev), cpu, &error_fatal);
object_unref(OBJECT(dev));
/* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */ /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */
ppc4xx_sdram_init(env, sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(uicdev, 14));
qdev_get_gpio_in(uicdev, 14), /* Enable SDRAM memory regions, this should be done by the firmware */
PPC440EP_SDRAM_NR_BANKS, ram_memories, ppc4xx_sdram_ddr_enable(PPC4xx_SDRAM_DDR(dev));
ram_bases, ram_sizes, 1);
/* PCI */ /* PCI */
dev = sysbus_create_varargs(TYPE_PPC4xx_PCI_HOST_BRIDGE, dev = sysbus_create_varargs(TYPE_PPC4xx_PCI_HOST_BRIDGE,
@ -289,8 +283,8 @@ static void bamboo_init(MachineState *machine)
/* If we're loading a kernel directly, we must load the device tree too. */ /* If we're loading a kernel directly, we must load the device tree too. */
if (kernel_filename) { if (kernel_filename) {
if (bamboo_load_device_tree(FDT_ADDR, machine->ram_size, RAMDISK_ADDR, if (bamboo_load_device_tree(machine, FDT_ADDR,
initrd_size, kernel_cmdline) < 0) { RAMDISK_ADDR, initrd_size) < 0) {
error_report("couldn't load device tree"); error_report("couldn't load device tree");
exit(1); exit(1);
} }

View File

@ -16,13 +16,15 @@
#include "qemu/module.h" #include "qemu/module.h"
#include "hw/irq.h" #include "hw/irq.h"
#include "exec/memory.h" #include "exec/memory.h"
#include "hw/ppc/ppc.h" #include "cpu.h"
#include "hw/ppc/ppc4xx.h"
#include "hw/qdev-properties.h" #include "hw/qdev-properties.h"
#include "hw/pci/pci.h" #include "hw/pci/pci.h"
#include "sysemu/block-backend.h" #include "sysemu/block-backend.h"
#include "sysemu/reset.h" #include "sysemu/reset.h"
#include "ppc440.h" #include "ppc440.h"
#include "qom/object.h" #include "qom/object.h"
#include "trace.h"
/*****************************************************************************/ /*****************************************************************************/
/* L2 Cache as SRAM */ /* L2 Cache as SRAM */
@ -378,10 +380,6 @@ enum {
PESDR1_RSTSTA = 0x365, PESDR1_RSTSTA = 0x365,
}; };
#define SDR0_DDR0_DDRM_ENCODE(n) ((((unsigned long)(n)) & 0x03) << 29)
#define SDR0_DDR0_DDRM_DDR1 0x20000000
#define SDR0_DDR0_DDRM_DDR2 0x40000000
static uint32_t dcr_read_sdr(void *opaque, int dcrn) static uint32_t dcr_read_sdr(void *opaque, int dcrn)
{ {
ppc4xx_sdr_t *sdr = opaque; ppc4xx_sdr_t *sdr = opaque;
@ -482,16 +480,6 @@ void ppc4xx_sdr_init(CPUPPCState *env)
/*****************************************************************************/ /*****************************************************************************/
/* SDRAM controller */ /* SDRAM controller */
typedef struct ppc440_sdram_t {
uint32_t addr;
int nbanks;
MemoryRegion containers[4]; /* used for clipping */
MemoryRegion *ram_memories;
hwaddr ram_bases[4];
hwaddr ram_sizes[4];
uint32_t bcr[4];
} ppc440_sdram_t;
enum { enum {
SDRAM0_CFGADDR = 0x10, SDRAM0_CFGADDR = 0x10,
SDRAM0_CFGDATA, SDRAM0_CFGDATA,
@ -506,39 +494,39 @@ enum {
SDRAM_PLBADDUHB = 0x50, SDRAM_PLBADDUHB = 0x50,
}; };
static uint32_t sdram_bcr(hwaddr ram_base, hwaddr ram_size) static uint32_t sdram_ddr2_bcr(hwaddr ram_base, hwaddr ram_size)
{ {
uint32_t bcr; uint32_t bcr;
switch (ram_size) { switch (ram_size) {
case (8 * MiB): case 8 * MiB:
bcr = 0xffc0; bcr = 0xffc0;
break; break;
case (16 * MiB): case 16 * MiB:
bcr = 0xff80; bcr = 0xff80;
break; break;
case (32 * MiB): case 32 * MiB:
bcr = 0xff00; bcr = 0xff00;
break; break;
case (64 * MiB): case 64 * MiB:
bcr = 0xfe00; bcr = 0xfe00;
break; break;
case (128 * MiB): case 128 * MiB:
bcr = 0xfc00; bcr = 0xfc00;
break; break;
case (256 * MiB): case 256 * MiB:
bcr = 0xf800; bcr = 0xf800;
break; break;
case (512 * MiB): case 512 * MiB:
bcr = 0xf000; bcr = 0xf000;
break; break;
case (1 * GiB): case 1 * GiB:
bcr = 0xe000; bcr = 0xe000;
break; break;
case (2 * GiB): case 2 * GiB:
bcr = 0xc000; bcr = 0xc000;
break; break;
case (4 * GiB): case 4 * GiB:
bcr = 0x8000; bcr = 0x8000;
break; break;
default: default:
@ -551,12 +539,12 @@ static uint32_t sdram_bcr(hwaddr ram_base, hwaddr ram_size)
return bcr; return bcr;
} }
static inline hwaddr sdram_base(uint32_t bcr) static inline hwaddr sdram_ddr2_base(uint32_t bcr)
{ {
return (bcr & 0xffe00000) << 2; return (bcr & 0xffe00000) << 2;
} }
static uint64_t sdram_size(uint32_t bcr) static uint64_t sdram_ddr2_size(uint32_t bcr)
{ {
uint64_t size; uint64_t size;
int sh; int sh;
@ -567,46 +555,66 @@ static uint64_t sdram_size(uint32_t bcr)
return size; return size;
} }
static void sdram_set_bcr(ppc440_sdram_t *sdram, int i, static void sdram_bank_map(Ppc4xxSdramBank *bank)
{
memory_region_init(&bank->container, NULL, "sdram-container", bank->size);
memory_region_add_subregion(&bank->container, 0, &bank->ram);
memory_region_add_subregion(get_system_memory(), bank->base,
&bank->container);
}
static void sdram_bank_unmap(Ppc4xxSdramBank *bank)
{
memory_region_del_subregion(get_system_memory(), &bank->container);
memory_region_del_subregion(&bank->container, &bank->ram);
object_unparent(OBJECT(&bank->container));
}
static void sdram_ddr2_set_bcr(Ppc4xxSdramDdr2State *sdram, int i,
uint32_t bcr, int enabled) uint32_t bcr, int enabled)
{ {
if (sdram->bcr[i] & 1) { if (sdram->bank[i].bcr & 1) {
/* First unmap RAM if enabled */ /* First unmap RAM if enabled */
memory_region_del_subregion(get_system_memory(), trace_ppc4xx_sdram_unmap(sdram_ddr2_base(sdram->bank[i].bcr),
&sdram->containers[i]); sdram_ddr2_size(sdram->bank[i].bcr));
memory_region_del_subregion(&sdram->containers[i], sdram_bank_unmap(&sdram->bank[i]);
&sdram->ram_memories[i]);
object_unparent(OBJECT(&sdram->containers[i]));
} }
sdram->bcr[i] = bcr & 0xffe0ffc1; sdram->bank[i].bcr = bcr & 0xffe0ffc1;
if (enabled && (bcr & 1)) { if (enabled && (bcr & 1)) {
memory_region_init(&sdram->containers[i], NULL, "sdram-containers", trace_ppc4xx_sdram_map(sdram_ddr2_base(bcr), sdram_ddr2_size(bcr));
sdram_size(bcr)); sdram_bank_map(&sdram->bank[i]);
memory_region_add_subregion(&sdram->containers[i], 0,
&sdram->ram_memories[i]);
memory_region_add_subregion(get_system_memory(),
sdram_base(bcr),
&sdram->containers[i]);
} }
} }
static void sdram_map_bcr(ppc440_sdram_t *sdram) static void sdram_ddr2_map_bcr(Ppc4xxSdramDdr2State *sdram)
{ {
int i; int i;
for (i = 0; i < sdram->nbanks; i++) { for (i = 0; i < sdram->nbanks; i++) {
if (sdram->ram_sizes[i] != 0) { if (sdram->bank[i].size) {
sdram_set_bcr(sdram, i, sdram_bcr(sdram->ram_bases[i], sdram_ddr2_set_bcr(sdram, i,
sdram->ram_sizes[i]), 1); sdram_ddr2_bcr(sdram->bank[i].base,
sdram->bank[i].size), 1);
} else { } else {
sdram_set_bcr(sdram, i, 0, 0); sdram_ddr2_set_bcr(sdram, i, 0, 0);
} }
} }
} }
static uint32_t dcr_read_sdram(void *opaque, int dcrn) static void sdram_ddr2_unmap_bcr(Ppc4xxSdramDdr2State *sdram)
{ {
ppc440_sdram_t *sdram = opaque; int i;
for (i = 0; i < sdram->nbanks; i++) {
if (sdram->bank[i].size) {
sdram_ddr2_set_bcr(sdram, i, sdram->bank[i].bcr & ~1, 0);
}
}
}
static uint32_t sdram_ddr2_dcr_read(void *opaque, int dcrn)
{
Ppc4xxSdramDdr2State *sdram = opaque;
uint32_t ret = 0; uint32_t ret = 0;
switch (dcrn) { switch (dcrn) {
@ -614,9 +622,9 @@ static uint32_t dcr_read_sdram(void *opaque, int dcrn)
case SDRAM_R1BAS: case SDRAM_R1BAS:
case SDRAM_R2BAS: case SDRAM_R2BAS:
case SDRAM_R3BAS: case SDRAM_R3BAS:
if (sdram->ram_sizes[dcrn - SDRAM_R0BAS]) { if (sdram->bank[dcrn - SDRAM_R0BAS].size) {
ret = sdram_bcr(sdram->ram_bases[dcrn - SDRAM_R0BAS], ret = sdram_ddr2_bcr(sdram->bank[dcrn - SDRAM_R0BAS].base,
sdram->ram_sizes[dcrn - SDRAM_R0BAS]); sdram->bank[dcrn - SDRAM_R0BAS].size);
} }
break; break;
case SDRAM_CONF1HB: case SDRAM_CONF1HB:
@ -635,7 +643,7 @@ static uint32_t dcr_read_sdram(void *opaque, int dcrn)
ret = 0x80000000; ret = 0x80000000;
break; break;
case 0x21: /* SDRAM_MCOPT2 */ case 0x21: /* SDRAM_MCOPT2 */
ret = 0x08000000; ret = sdram->mcopt2;
break; break;
case 0x40: /* SDRAM_MB0CF */ case 0x40: /* SDRAM_MB0CF */
ret = 0x00008001; ret = 0x00008001;
@ -657,9 +665,11 @@ static uint32_t dcr_read_sdram(void *opaque, int dcrn)
return ret; return ret;
} }
static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val) #define SDRAM_DDR2_MCOPT2_DCEN BIT(27)
static void sdram_ddr2_dcr_write(void *opaque, int dcrn, uint32_t val)
{ {
ppc440_sdram_t *sdram = opaque; Ppc4xxSdramDdr2State *sdram = opaque;
switch (dcrn) { switch (dcrn) {
case SDRAM_R0BAS: case SDRAM_R0BAS:
@ -679,6 +689,21 @@ static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val)
switch (sdram->addr) { switch (sdram->addr) {
case 0x00: /* B0CR */ case 0x00: /* B0CR */
break; break;
case 0x21: /* SDRAM_MCOPT2 */
if (!(sdram->mcopt2 & SDRAM_DDR2_MCOPT2_DCEN) &&
(val & SDRAM_DDR2_MCOPT2_DCEN)) {
trace_ppc4xx_sdram_enable("enable");
/* validate all RAM mappings */
sdram_ddr2_map_bcr(sdram);
sdram->mcopt2 |= SDRAM_DDR2_MCOPT2_DCEN;
} else if ((sdram->mcopt2 & SDRAM_DDR2_MCOPT2_DCEN) &&
!(val & SDRAM_DDR2_MCOPT2_DCEN)) {
trace_ppc4xx_sdram_enable("disable");
/* invalidate all RAM mappings */
sdram_ddr2_unmap_bcr(sdram);
sdram->mcopt2 &= ~SDRAM_DDR2_MCOPT2_DCEN;
}
break;
default: default:
break; break;
} }
@ -688,54 +713,96 @@ static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val)
} }
} }
static void sdram_reset(void *opaque) static void ppc4xx_sdram_ddr2_reset(DeviceState *dev)
{ {
ppc440_sdram_t *sdram = opaque; Ppc4xxSdramDdr2State *sdram = PPC4xx_SDRAM_DDR2(dev);
sdram->addr = 0; sdram->addr = 0;
sdram->mcopt2 = 0;
} }
void ppc440_sdram_init(CPUPPCState *env, int nbanks, static void ppc4xx_sdram_ddr2_realize(DeviceState *dev, Error **errp)
MemoryRegion *ram_memories,
hwaddr *ram_bases, hwaddr *ram_sizes,
int do_init)
{ {
ppc440_sdram_t *sdram; Ppc4xxSdramDdr2State *s = PPC4xx_SDRAM_DDR2(dev);
Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev);
/*
* SoC also has 4 GiB but that causes problem with 32 bit
* builds (4*GiB overflows the 32 bit ram_addr_t).
*/
const ram_addr_t valid_bank_sizes[] = {
2 * GiB, 1 * GiB, 512 * MiB, 256 * MiB, 128 * MiB,
64 * MiB, 32 * MiB, 16 * MiB, 8 * MiB, 0
};
sdram = g_malloc0(sizeof(*sdram)); if (s->nbanks < 1 || s->nbanks > 4) {
sdram->nbanks = nbanks; error_setg(errp, "Invalid number of RAM banks");
sdram->ram_memories = ram_memories; return;
memcpy(sdram->ram_bases, ram_bases, nbanks * sizeof(hwaddr));
memcpy(sdram->ram_sizes, ram_sizes, nbanks * sizeof(hwaddr));
qemu_register_reset(&sdram_reset, sdram);
ppc_dcr_register(env, SDRAM0_CFGADDR,
sdram, &dcr_read_sdram, &dcr_write_sdram);
ppc_dcr_register(env, SDRAM0_CFGDATA,
sdram, &dcr_read_sdram, &dcr_write_sdram);
if (do_init) {
sdram_map_bcr(sdram);
} }
if (!s->dram_mr) {
error_setg(errp, "Missing dram memory region");
return;
}
ppc4xx_sdram_banks(s->dram_mr, s->nbanks, s->bank, valid_bank_sizes);
ppc_dcr_register(env, SDRAM_R0BAS, ppc4xx_dcr_register(dcr, SDRAM0_CFGADDR,
sdram, &dcr_read_sdram, &dcr_write_sdram); s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
ppc_dcr_register(env, SDRAM_R1BAS, ppc4xx_dcr_register(dcr, SDRAM0_CFGDATA,
sdram, &dcr_read_sdram, &dcr_write_sdram); s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
ppc_dcr_register(env, SDRAM_R2BAS,
sdram, &dcr_read_sdram, &dcr_write_sdram); ppc4xx_dcr_register(dcr, SDRAM_R0BAS,
ppc_dcr_register(env, SDRAM_R3BAS, s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
sdram, &dcr_read_sdram, &dcr_write_sdram); ppc4xx_dcr_register(dcr, SDRAM_R1BAS,
ppc_dcr_register(env, SDRAM_CONF1HB, s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
sdram, &dcr_read_sdram, &dcr_write_sdram); ppc4xx_dcr_register(dcr, SDRAM_R2BAS,
ppc_dcr_register(env, SDRAM_PLBADDULL, s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
sdram, &dcr_read_sdram, &dcr_write_sdram); ppc4xx_dcr_register(dcr, SDRAM_R3BAS,
ppc_dcr_register(env, SDRAM_CONF1LL, s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
sdram, &dcr_read_sdram, &dcr_write_sdram); ppc4xx_dcr_register(dcr, SDRAM_CONF1HB,
ppc_dcr_register(env, SDRAM_CONFPATHB, s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
sdram, &dcr_read_sdram, &dcr_write_sdram); ppc4xx_dcr_register(dcr, SDRAM_PLBADDULL,
ppc_dcr_register(env, SDRAM_PLBADDUHB, s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
sdram, &dcr_read_sdram, &dcr_write_sdram); ppc4xx_dcr_register(dcr, SDRAM_CONF1LL,
s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
ppc4xx_dcr_register(dcr, SDRAM_CONFPATHB,
s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
ppc4xx_dcr_register(dcr, SDRAM_PLBADDUHB,
s, &sdram_ddr2_dcr_read, &sdram_ddr2_dcr_write);
} }
static Property ppc4xx_sdram_ddr2_props[] = {
DEFINE_PROP_LINK("dram", Ppc4xxSdramDdr2State, dram_mr, TYPE_MEMORY_REGION,
MemoryRegion *),
DEFINE_PROP_UINT32("nbanks", Ppc4xxSdramDdr2State, nbanks, 4),
DEFINE_PROP_END_OF_LIST(),
};
static void ppc4xx_sdram_ddr2_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = ppc4xx_sdram_ddr2_realize;
dc->reset = ppc4xx_sdram_ddr2_reset;
/* Reason: only works as function of a ppc4xx SoC */
dc->user_creatable = false;
device_class_set_props(dc, ppc4xx_sdram_ddr2_props);
}
void ppc4xx_sdram_ddr2_enable(Ppc4xxSdramDdr2State *s)
{
sdram_ddr2_dcr_write(s, SDRAM0_CFGADDR, 0x21);
sdram_ddr2_dcr_write(s, SDRAM0_CFGDATA, 0x08000000);
}
static const TypeInfo ppc4xx_types[] = {
{
.name = TYPE_PPC4xx_SDRAM_DDR2,
.parent = TYPE_PPC4xx_DCR_DEVICE,
.instance_size = sizeof(Ppc4xxSdramDdr2State),
.class_init = ppc4xx_sdram_ddr2_class_init,
}
};
DEFINE_TYPES(ppc4xx_types)
/*****************************************************************************/ /*****************************************************************************/
/* PLB to AHB bridge */ /* PLB to AHB bridge */
enum { enum {

View File

@ -38,28 +38,6 @@
/*****************************************************************************/ /*****************************************************************************/
/* SDRAM controller */ /* SDRAM controller */
typedef struct ppc4xx_sdram_t ppc4xx_sdram_t;
struct ppc4xx_sdram_t {
uint32_t addr;
int nbanks;
MemoryRegion containers[4]; /* used for clipping */
MemoryRegion *ram_memories;
hwaddr ram_bases[4];
hwaddr ram_sizes[4];
uint32_t besr0;
uint32_t besr1;
uint32_t bear;
uint32_t cfg;
uint32_t status;
uint32_t rtr;
uint32_t pmit;
uint32_t bcr[4];
uint32_t tr;
uint32_t ecccfg;
uint32_t eccesr;
qemu_irq irq;
};
enum { enum {
SDRAM0_CFGADDR = 0x010, SDRAM0_CFGADDR = 0x010,
SDRAM0_CFGDATA = 0x011, SDRAM0_CFGDATA = 0x011,
@ -70,37 +48,37 @@ enum {
* there are type inconsistencies, mixing hwaddr, target_ulong * there are type inconsistencies, mixing hwaddr, target_ulong
* and uint32_t * and uint32_t
*/ */
static uint32_t sdram_bcr(hwaddr ram_base, hwaddr ram_size) static uint32_t sdram_ddr_bcr(hwaddr ram_base, hwaddr ram_size)
{ {
uint32_t bcr; uint32_t bcr;
switch (ram_size) { switch (ram_size) {
case 4 * MiB: case 4 * MiB:
bcr = 0x00000000; bcr = 0;
break; break;
case 8 * MiB: case 8 * MiB:
bcr = 0x00020000; bcr = 0x20000;
break; break;
case 16 * MiB: case 16 * MiB:
bcr = 0x00040000; bcr = 0x40000;
break; break;
case 32 * MiB: case 32 * MiB:
bcr = 0x00060000; bcr = 0x60000;
break; break;
case 64 * MiB: case 64 * MiB:
bcr = 0x00080000; bcr = 0x80000;
break; break;
case 128 * MiB: case 128 * MiB:
bcr = 0x000A0000; bcr = 0xA0000;
break; break;
case 256 * MiB: case 256 * MiB:
bcr = 0x000C0000; bcr = 0xC0000;
break; break;
default: default:
qemu_log_mask(LOG_GUEST_ERROR, qemu_log_mask(LOG_GUEST_ERROR,
"%s: invalid RAM size 0x%" HWADDR_PRIx "\n", __func__, "%s: invalid RAM size 0x%" HWADDR_PRIx "\n", __func__,
ram_size); ram_size);
return 0x00000000; return 0;
} }
bcr |= ram_base & 0xFF800000; bcr |= ram_base & 0xFF800000;
bcr |= 1; bcr |= 1;
@ -108,12 +86,12 @@ static uint32_t sdram_bcr(hwaddr ram_base, hwaddr ram_size)
return bcr; return bcr;
} }
static inline hwaddr sdram_base(uint32_t bcr) static inline hwaddr sdram_ddr_base(uint32_t bcr)
{ {
return bcr & 0xFF800000; return bcr & 0xFF800000;
} }
static target_ulong sdram_size(uint32_t bcr) static target_ulong sdram_ddr_size(uint32_t bcr)
{ {
target_ulong size; target_ulong size;
int sh; int sh;
@ -128,64 +106,63 @@ static target_ulong sdram_size(uint32_t bcr)
return size; return size;
} }
static void sdram_set_bcr(ppc4xx_sdram_t *sdram, int i, static void sdram_ddr_set_bcr(Ppc4xxSdramDdrState *sdram, int i,
uint32_t bcr, int enabled) uint32_t bcr, int enabled)
{ {
if (sdram->bcr[i] & 0x00000001) { if (sdram->bank[i].bcr & 1) {
/* Unmap RAM */ /* Unmap RAM */
trace_ppc4xx_sdram_unmap(sdram_base(sdram->bcr[i]), trace_ppc4xx_sdram_unmap(sdram_ddr_base(sdram->bank[i].bcr),
sdram_size(sdram->bcr[i])); sdram_ddr_size(sdram->bank[i].bcr));
memory_region_del_subregion(get_system_memory(), memory_region_del_subregion(get_system_memory(),
&sdram->containers[i]); &sdram->bank[i].container);
memory_region_del_subregion(&sdram->containers[i], memory_region_del_subregion(&sdram->bank[i].container,
&sdram->ram_memories[i]); &sdram->bank[i].ram);
object_unparent(OBJECT(&sdram->containers[i])); object_unparent(OBJECT(&sdram->bank[i].container));
} }
sdram->bcr[i] = bcr & 0xFFDEE001; sdram->bank[i].bcr = bcr & 0xFFDEE001;
if (enabled && (bcr & 0x00000001)) { if (enabled && (bcr & 1)) {
trace_ppc4xx_sdram_map(sdram_base(bcr), sdram_size(bcr)); trace_ppc4xx_sdram_map(sdram_ddr_base(bcr), sdram_ddr_size(bcr));
memory_region_init(&sdram->containers[i], NULL, "sdram-containers", memory_region_init(&sdram->bank[i].container, NULL, "sdram-container",
sdram_size(bcr)); sdram_ddr_size(bcr));
memory_region_add_subregion(&sdram->containers[i], 0, memory_region_add_subregion(&sdram->bank[i].container, 0,
&sdram->ram_memories[i]); &sdram->bank[i].ram);
memory_region_add_subregion(get_system_memory(), memory_region_add_subregion(get_system_memory(),
sdram_base(bcr), sdram_ddr_base(bcr),
&sdram->containers[i]); &sdram->bank[i].container);
} }
} }
static void sdram_map_bcr(ppc4xx_sdram_t *sdram) static void sdram_ddr_map_bcr(Ppc4xxSdramDdrState *sdram)
{ {
int i; int i;
for (i = 0; i < sdram->nbanks; i++) { for (i = 0; i < sdram->nbanks; i++) {
if (sdram->ram_sizes[i] != 0) { if (sdram->bank[i].size != 0) {
sdram_set_bcr(sdram, i, sdram_bcr(sdram->ram_bases[i], sdram_ddr_set_bcr(sdram, i, sdram_ddr_bcr(sdram->bank[i].base,
sdram->ram_sizes[i]), 1); sdram->bank[i].size), 1);
} else { } else {
sdram_set_bcr(sdram, i, 0x00000000, 0); sdram_ddr_set_bcr(sdram, i, 0, 0);
} }
} }
} }
static void sdram_unmap_bcr(ppc4xx_sdram_t *sdram) static void sdram_ddr_unmap_bcr(Ppc4xxSdramDdrState *sdram)
{ {
int i; int i;
for (i = 0; i < sdram->nbanks; i++) { for (i = 0; i < sdram->nbanks; i++) {
trace_ppc4xx_sdram_unmap(sdram_base(sdram->bcr[i]), trace_ppc4xx_sdram_unmap(sdram_ddr_base(sdram->bank[i].bcr),
sdram_size(sdram->bcr[i])); sdram_ddr_size(sdram->bank[i].bcr));
memory_region_del_subregion(get_system_memory(), memory_region_del_subregion(get_system_memory(),
&sdram->ram_memories[i]); &sdram->bank[i].ram);
} }
} }
static uint32_t dcr_read_sdram(void *opaque, int dcrn) static uint32_t sdram_ddr_dcr_read(void *opaque, int dcrn)
{ {
ppc4xx_sdram_t *sdram; Ppc4xxSdramDdrState *sdram = opaque;
uint32_t ret; uint32_t ret;
sdram = opaque;
switch (dcrn) { switch (dcrn) {
case SDRAM0_CFGADDR: case SDRAM0_CFGADDR:
ret = sdram->addr; ret = sdram->addr;
@ -214,16 +191,16 @@ static uint32_t dcr_read_sdram(void *opaque, int dcrn)
ret = sdram->pmit; ret = sdram->pmit;
break; break;
case 0x40: /* SDRAM_B0CR */ case 0x40: /* SDRAM_B0CR */
ret = sdram->bcr[0]; ret = sdram->bank[0].bcr;
break; break;
case 0x44: /* SDRAM_B1CR */ case 0x44: /* SDRAM_B1CR */
ret = sdram->bcr[1]; ret = sdram->bank[1].bcr;
break; break;
case 0x48: /* SDRAM_B2CR */ case 0x48: /* SDRAM_B2CR */
ret = sdram->bcr[2]; ret = sdram->bank[2].bcr;
break; break;
case 0x4C: /* SDRAM_B3CR */ case 0x4C: /* SDRAM_B3CR */
ret = sdram->bcr[3]; ret = sdram->bank[3].bcr;
break; break;
case 0x80: /* SDRAM_TR */ case 0x80: /* SDRAM_TR */
ret = -1; /* ? */ ret = -1; /* ? */
@ -241,18 +218,17 @@ static uint32_t dcr_read_sdram(void *opaque, int dcrn)
break; break;
default: default:
/* Avoid gcc warning */ /* Avoid gcc warning */
ret = 0x00000000; ret = 0;
break; break;
} }
return ret; return ret;
} }
static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val) static void sdram_ddr_dcr_write(void *opaque, int dcrn, uint32_t val)
{ {
ppc4xx_sdram_t *sdram; Ppc4xxSdramDdrState *sdram = opaque;
sdram = opaque;
switch (dcrn) { switch (dcrn) {
case SDRAM0_CFGADDR: case SDRAM0_CFGADDR:
sdram->addr = val; sdram->addr = val;
@ -273,12 +249,12 @@ static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val)
if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) { if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) {
trace_ppc4xx_sdram_enable("enable"); trace_ppc4xx_sdram_enable("enable");
/* validate all RAM mappings */ /* validate all RAM mappings */
sdram_map_bcr(sdram); sdram_ddr_map_bcr(sdram);
sdram->status &= ~0x80000000; sdram->status &= ~0x80000000;
} else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) { } else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) {
trace_ppc4xx_sdram_enable("disable"); trace_ppc4xx_sdram_enable("disable");
/* invalidate all RAM mappings */ /* invalidate all RAM mappings */
sdram_unmap_bcr(sdram); sdram_ddr_unmap_bcr(sdram);
sdram->status |= 0x80000000; sdram->status |= 0x80000000;
} }
if (!(sdram->cfg & 0x40000000) && (val & 0x40000000)) { if (!(sdram->cfg & 0x40000000) && (val & 0x40000000)) {
@ -298,16 +274,16 @@ static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val)
sdram->pmit = (val & 0xF8000000) | 0x07C00000; sdram->pmit = (val & 0xF8000000) | 0x07C00000;
break; break;
case 0x40: /* SDRAM_B0CR */ case 0x40: /* SDRAM_B0CR */
sdram_set_bcr(sdram, 0, val, sdram->cfg & 0x80000000); sdram_ddr_set_bcr(sdram, 0, val, sdram->cfg & 0x80000000);
break; break;
case 0x44: /* SDRAM_B1CR */ case 0x44: /* SDRAM_B1CR */
sdram_set_bcr(sdram, 1, val, sdram->cfg & 0x80000000); sdram_ddr_set_bcr(sdram, 1, val, sdram->cfg & 0x80000000);
break; break;
case 0x48: /* SDRAM_B2CR */ case 0x48: /* SDRAM_B2CR */
sdram_set_bcr(sdram, 2, val, sdram->cfg & 0x80000000); sdram_ddr_set_bcr(sdram, 2, val, sdram->cfg & 0x80000000);
break; break;
case 0x4C: /* SDRAM_B3CR */ case 0x4C: /* SDRAM_B3CR */
sdram_set_bcr(sdram, 3, val, sdram->cfg & 0x80000000); sdram_ddr_set_bcr(sdram, 3, val, sdram->cfg & 0x80000000);
break; break;
case 0x80: /* SDRAM_TR */ case 0x80: /* SDRAM_TR */
sdram->tr = val & 0x018FC01F; sdram->tr = val & 0x018FC01F;
@ -331,52 +307,73 @@ static void dcr_write_sdram(void *opaque, int dcrn, uint32_t val)
} }
} }
static void sdram_reset(void *opaque) static void ppc4xx_sdram_ddr_reset(DeviceState *dev)
{ {
ppc4xx_sdram_t *sdram; Ppc4xxSdramDdrState *sdram = PPC4xx_SDRAM_DDR(dev);
sdram = opaque; sdram->addr = 0;
sdram->addr = 0x00000000; sdram->bear = 0;
sdram->bear = 0x00000000; sdram->besr0 = 0; /* No error */
sdram->besr0 = 0x00000000; /* No error */ sdram->besr1 = 0; /* No error */
sdram->besr1 = 0x00000000; /* No error */ sdram->cfg = 0;
sdram->cfg = 0x00000000; sdram->ecccfg = 0; /* No ECC */
sdram->ecccfg = 0x00000000; /* No ECC */ sdram->eccesr = 0; /* No error */
sdram->eccesr = 0x00000000; /* No error */
sdram->pmit = 0x07C00000; sdram->pmit = 0x07C00000;
sdram->rtr = 0x05F00000; sdram->rtr = 0x05F00000;
sdram->tr = 0x00854009; sdram->tr = 0x00854009;
/* We pre-initialize RAM banks */ /* We pre-initialize RAM banks */
sdram->status = 0x00000000; sdram->status = 0;
sdram->cfg = 0x00800000; sdram->cfg = 0x00800000;
} }
void ppc4xx_sdram_init(CPUPPCState *env, qemu_irq irq, int nbanks, static void ppc4xx_sdram_ddr_realize(DeviceState *dev, Error **errp)
MemoryRegion *ram_memories,
hwaddr *ram_bases,
hwaddr *ram_sizes,
int do_init)
{ {
ppc4xx_sdram_t *sdram; Ppc4xxSdramDdrState *s = PPC4xx_SDRAM_DDR(dev);
Ppc4xxDcrDeviceState *dcr = PPC4xx_DCR_DEVICE(dev);
const ram_addr_t valid_bank_sizes[] = {
256 * MiB, 128 * MiB, 64 * MiB, 32 * MiB, 16 * MiB, 8 * MiB, 4 * MiB, 0
};
sdram = g_new0(ppc4xx_sdram_t, 1); if (s->nbanks < 1 || s->nbanks > 4) {
sdram->irq = irq; error_setg(errp, "Invalid number of RAM banks");
sdram->nbanks = nbanks; return;
sdram->ram_memories = ram_memories;
memset(sdram->ram_bases, 0, 4 * sizeof(hwaddr));
memcpy(sdram->ram_bases, ram_bases,
nbanks * sizeof(hwaddr));
memset(sdram->ram_sizes, 0, 4 * sizeof(hwaddr));
memcpy(sdram->ram_sizes, ram_sizes,
nbanks * sizeof(hwaddr));
qemu_register_reset(&sdram_reset, sdram);
ppc_dcr_register(env, SDRAM0_CFGADDR,
sdram, &dcr_read_sdram, &dcr_write_sdram);
ppc_dcr_register(env, SDRAM0_CFGDATA,
sdram, &dcr_read_sdram, &dcr_write_sdram);
if (do_init) {
sdram_map_bcr(sdram);
} }
if (!s->dram_mr) {
error_setg(errp, "Missing dram memory region");
return;
}
ppc4xx_sdram_banks(s->dram_mr, s->nbanks, s->bank, valid_bank_sizes);
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
ppc4xx_dcr_register(dcr, SDRAM0_CFGADDR,
s, &sdram_ddr_dcr_read, &sdram_ddr_dcr_write);
ppc4xx_dcr_register(dcr, SDRAM0_CFGDATA,
s, &sdram_ddr_dcr_read, &sdram_ddr_dcr_write);
}
static Property ppc4xx_sdram_ddr_props[] = {
DEFINE_PROP_LINK("dram", Ppc4xxSdramDdrState, dram_mr, TYPE_MEMORY_REGION,
MemoryRegion *),
DEFINE_PROP_UINT32("nbanks", Ppc4xxSdramDdrState, nbanks, 4),
DEFINE_PROP_END_OF_LIST(),
};
static void ppc4xx_sdram_ddr_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = ppc4xx_sdram_ddr_realize;
dc->reset = ppc4xx_sdram_ddr_reset;
/* Reason: only works as function of a ppc4xx SoC */
dc->user_creatable = false;
device_class_set_props(dc, ppc4xx_sdram_ddr_props);
}
void ppc4xx_sdram_ddr_enable(Ppc4xxSdramDdrState *s)
{
sdram_ddr_dcr_write(s, SDRAM0_CFGADDR, 0x20);
sdram_ddr_dcr_write(s, SDRAM0_CFGDATA, 0x80000000);
} }
/* /*
@ -390,8 +387,7 @@ void ppc4xx_sdram_init(CPUPPCState *env, qemu_irq irq, int nbanks,
* sizes varies by SoC. * sizes varies by SoC.
*/ */
void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks, void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks,
MemoryRegion ram_memories[], Ppc4xxSdramBank ram_banks[],
hwaddr ram_bases[], hwaddr ram_sizes[],
const ram_addr_t sdram_bank_sizes[]) const ram_addr_t sdram_bank_sizes[])
{ {
ram_addr_t size_left = memory_region_size(ram); ram_addr_t size_left = memory_region_size(ram);
@ -406,13 +402,13 @@ void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks,
if (bank_size <= size_left) { if (bank_size <= size_left) {
char name[32]; char name[32];
ram_bases[i] = base; ram_banks[i].base = base;
ram_sizes[i] = bank_size; ram_banks[i].size = bank_size;
base += bank_size; base += bank_size;
size_left -= bank_size; size_left -= bank_size;
snprintf(name, sizeof(name), "ppc4xx.sdram%d", i); snprintf(name, sizeof(name), "ppc4xx.sdram%d", i);
memory_region_init_alias(&ram_memories[i], NULL, name, ram, memory_region_init_alias(&ram_banks[i].ram, NULL, name, ram,
ram_bases[i], ram_sizes[i]); ram_banks[i].base, ram_banks[i].size);
break; break;
} }
} }
@ -967,6 +963,11 @@ static void ppc4xx_dcr_class_init(ObjectClass *oc, void *data)
static const TypeInfo ppc4xx_types[] = { static const TypeInfo ppc4xx_types[] = {
{ {
.name = TYPE_PPC4xx_SDRAM_DDR,
.parent = TYPE_PPC4xx_DCR_DEVICE,
.instance_size = sizeof(Ppc4xxSdramDdrState),
.class_init = ppc4xx_sdram_ddr_class_init,
}, {
.name = TYPE_PPC4xx_MAL, .name = TYPE_PPC4xx_MAL,
.parent = TYPE_PPC4xx_DCR_DEVICE, .parent = TYPE_PPC4xx_DCR_DEVICE,
.instance_size = sizeof(Ppc4xxMalState), .instance_size = sizeof(Ppc4xxMalState),

View File

@ -73,14 +73,6 @@
#define OPB_FREQ 115000000 #define OPB_FREQ 115000000
#define EBC_FREQ 115000000 #define EBC_FREQ 115000000
#define UART_FREQ 11059200 #define UART_FREQ 11059200
#define SDRAM_NR_BANKS 4
/* The SoC could also handle 4 GiB but firmware does not work with that. */
/* Maybe it overflows a signed 32 bit number somewhere? */
static const ram_addr_t ppc460ex_sdram_bank_sizes[] = {
2 * GiB, 1 * GiB, 512 * MiB, 256 * MiB, 128 * MiB, 64 * MiB,
32 * MiB, 0
};
struct boot_info { struct boot_info {
uint32_t dt_base; uint32_t dt_base;
@ -131,13 +123,12 @@ static int sam460ex_load_uboot(void)
return 0; return 0;
} }
static int sam460ex_load_device_tree(hwaddr addr, static int sam460ex_load_device_tree(MachineState *machine,
uint32_t ramsize, hwaddr addr,
hwaddr initrd_base, hwaddr initrd_base,
hwaddr initrd_size, hwaddr initrd_size)
const char *kernel_cmdline)
{ {
uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(ramsize) }; uint32_t mem_reg_property[] = { 0, 0, cpu_to_be32(machine->ram_size) };
char *filename; char *filename;
int fdt_size; int fdt_size;
void *fdt; void *fdt;
@ -171,7 +162,8 @@ static int sam460ex_load_device_tree(hwaddr addr,
qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
(initrd_base + initrd_size)); (initrd_base + initrd_size));
qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline); qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
machine->kernel_cmdline);
/* Copy data from the host device tree into the guest. Since the guest can /* Copy data from the host device tree into the guest. Since the guest can
* directly access the timebase without host involvement, we must expose * directly access the timebase without host involvement, we must expose
@ -208,7 +200,9 @@ static int sam460ex_load_device_tree(hwaddr addr,
EBC_FREQ); EBC_FREQ);
rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr); rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
g_free(fdt);
/* Set machine->fdt for 'dumpdtb' QMP/HMP command */
machine->fdt = fdt;
return fdt_size; return fdt_size;
} }
@ -274,9 +268,6 @@ static void sam460ex_init(MachineState *machine)
{ {
MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *isa = g_new(MemoryRegion, 1); MemoryRegion *isa = g_new(MemoryRegion, 1);
MemoryRegion *ram_memories = g_new(MemoryRegion, SDRAM_NR_BANKS);
hwaddr ram_bases[SDRAM_NR_BANKS] = {0};
hwaddr ram_sizes[SDRAM_NR_BANKS] = {0};
MemoryRegion *l2cache_ram = g_new(MemoryRegion, 1); MemoryRegion *l2cache_ram = g_new(MemoryRegion, 1);
DeviceState *uic[4]; DeviceState *uic[4];
int i; int i;
@ -343,22 +334,37 @@ static void sam460ex_init(MachineState *machine)
} }
/* SDRAM controller */ /* SDRAM controller */
/* put all RAM on first bank because board has one slot /* The SoC could also handle 4 GiB but firmware does not work with that. */
* and firmware only checks that */ if (machine->ram_size > 2 * GiB) {
ppc4xx_sdram_banks(machine->ram, 1, ram_memories, ram_bases, ram_sizes, error_report("Memory over 2 GiB is not supported");
ppc460ex_sdram_bank_sizes); exit(1);
}
/* Firmware needs at least 64 MiB */
if (machine->ram_size < 64 * MiB) {
error_report("Memory below 64 MiB is not supported");
exit(1);
}
dev = qdev_new(TYPE_PPC4xx_SDRAM_DDR2);
object_property_set_link(OBJECT(dev), "dram", OBJECT(machine->ram),
&error_abort);
/*
* Put all RAM on first bank because board has one slot
* and firmware only checks that
*/
object_property_set_int(OBJECT(dev), "nbanks", 1, &error_abort);
ppc4xx_dcr_realize(PPC4xx_DCR_DEVICE(dev), cpu, &error_fatal);
object_unref(OBJECT(dev));
/* FIXME: does 460EX have ECC interrupts? */ /* FIXME: does 460EX have ECC interrupts? */
ppc440_sdram_init(env, SDRAM_NR_BANKS, ram_memories, /* Enable SDRAM memory regions as we may boot without firmware */
ram_bases, ram_sizes, 1); ppc4xx_sdram_ddr2_enable(PPC4xx_SDRAM_DDR2(dev));
/* IIC controllers and devices */ /* IIC controllers and devices */
dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600700, dev = sysbus_create_simple(TYPE_PPC4xx_I2C, 0x4ef600700,
qdev_get_gpio_in(uic[0], 2)); qdev_get_gpio_in(uic[0], 2));
i2c = PPC4xx_I2C(dev)->bus; i2c = PPC4xx_I2C(dev)->bus;
/* SPD EEPROM on RAM module */ /* SPD EEPROM on RAM module */
spd_data = spd_data_generate(ram_sizes[0] < 128 * MiB ? DDR : DDR2, spd_data = spd_data_generate(machine->ram_size < 128 * MiB ? DDR : DDR2,
ram_sizes[0]); machine->ram_size);
spd_data[20] = 4; /* SO-DIMM module */ spd_data[20] = 4; /* SO-DIMM module */
smbus_eeprom_init_one(i2c, 0x50, spd_data); smbus_eeprom_init_one(i2c, 0x50, spd_data);
/* RTC */ /* RTC */
@ -496,9 +502,8 @@ static void sam460ex_init(MachineState *machine)
if (machine->kernel_filename) { if (machine->kernel_filename) {
int dt_size; int dt_size;
dt_size = sam460ex_load_device_tree(FDT_ADDR, machine->ram_size, dt_size = sam460ex_load_device_tree(machine, FDT_ADDR,
RAMDISK_ADDR, initrd_size, RAMDISK_ADDR, initrd_size);
machine->kernel_cmdline);
boot_info->dt_base = FDT_ADDR; boot_info->dt_base = FDT_ADDR;
boot_info->dt_size = dt_size; boot_info->dt_size = dt_size;

View File

@ -1713,6 +1713,9 @@ static void spapr_machine_reset(MachineState *machine)
spapr->fdt_initial_size = spapr->fdt_size; spapr->fdt_initial_size = spapr->fdt_size;
spapr->fdt_blob = fdt; spapr->fdt_blob = fdt;
/* Set machine->fdt for 'dumpdtb' QMP/HMP command */
machine->fdt = fdt;
/* Set up the entry state */ /* Set up the entry state */
first_ppc_cpu->env.gpr[5] = 0; first_ppc_cpu->env.gpr[5] = 0;

View File

@ -1256,6 +1256,14 @@ target_ulong do_client_architecture_support(PowerPCCPU *cpu,
spapr->fdt_initial_size = spapr->fdt_size; spapr->fdt_initial_size = spapr->fdt_size;
spapr->fdt_blob = fdt; spapr->fdt_blob = fdt;
/*
* Set the machine->fdt pointer again since we just freed
* it above (by freeing spapr->fdt_blob). We set this
* pointer to enable support for the 'dumpdtb' QMP/HMP
* command.
*/
MACHINE(spapr)->fdt = fdt;
return H_SUCCESS; return H_SUCCESS;
} }

View File

@ -2045,7 +2045,7 @@ static int spapr_phb_children_reset(Object *child, void *opaque)
DeviceState *dev = (DeviceState *) object_dynamic_cast(child, TYPE_DEVICE); DeviceState *dev = (DeviceState *) object_dynamic_cast(child, TYPE_DEVICE);
if (dev) { if (dev) {
device_legacy_reset(dev); device_cold_reset(dev);
} }
return 0; return 0;

View File

@ -45,6 +45,8 @@
#include "hw/qdev-properties.h" #include "hw/qdev-properties.h"
#include "ppc405.h" #include "ppc405.h"
#include <libfdt.h>
#define EPAPR_MAGIC (0x45504150) #define EPAPR_MAGIC (0x45504150)
#define FLASH_SIZE (16 * MiB) #define FLASH_SIZE (16 * MiB)
@ -144,11 +146,10 @@ static void main_cpu_reset(void *opaque)
} }
#define BINARY_DEVICE_TREE_FILE "virtex-ml507.dtb" #define BINARY_DEVICE_TREE_FILE "virtex-ml507.dtb"
static int xilinx_load_device_tree(hwaddr addr, static int xilinx_load_device_tree(MachineState *machine,
uint32_t ramsize, hwaddr addr,
hwaddr initrd_base, hwaddr initrd_base,
hwaddr initrd_size, hwaddr initrd_size)
const char *kernel_cmdline)
{ {
char *path; char *path;
int fdt_size; int fdt_size;
@ -190,18 +191,21 @@ static int xilinx_load_device_tree(hwaddr addr,
error_report("couldn't set /chosen/linux,initrd-end"); error_report("couldn't set /chosen/linux,initrd-end");
} }
r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline); r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
machine->kernel_cmdline);
if (r < 0) if (r < 0)
fprintf(stderr, "couldn't set /chosen/bootargs\n"); fprintf(stderr, "couldn't set /chosen/bootargs\n");
cpu_physical_memory_write(addr, fdt, fdt_size); cpu_physical_memory_write(addr, fdt, fdt_size);
g_free(fdt);
/* Set machine->fdt for 'dumpdtb' QMP/HMP command */
machine->fdt = fdt;
return fdt_size; return fdt_size;
} }
static void virtex_init(MachineState *machine) static void virtex_init(MachineState *machine)
{ {
const char *kernel_filename = machine->kernel_filename; const char *kernel_filename = machine->kernel_filename;
const char *kernel_cmdline = machine->kernel_cmdline;
hwaddr initrd_base = 0; hwaddr initrd_base = 0;
int initrd_size = 0; int initrd_size = 0;
MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *address_space_mem = get_system_memory();
@ -294,9 +298,8 @@ static void virtex_init(MachineState *machine)
boot_info.fdt = high + (8192 * 2); boot_info.fdt = high + (8192 * 2);
boot_info.fdt &= ~8191; boot_info.fdt &= ~8191;
xilinx_load_device_tree(boot_info.fdt, machine->ram_size, xilinx_load_device_tree(machine, boot_info.fdt,
initrd_base, initrd_size, initrd_base, initrd_size);
kernel_cmdline);
} }
env->load_info = &boot_info; env->load_info = &boot_info;
} }

View File

@ -634,6 +634,9 @@ static void sifive_u_machine_init(MachineState *machine)
start_addr_hi32 = (uint64_t)start_addr >> 32; start_addr_hi32 = (uint64_t)start_addr >> 32;
} }
/* Set machine->fdt for 'dumpdtb' QMP/HMP command */
machine->fdt = s->fdt;
/* reset vector */ /* reset vector */
uint32_t reset_vec[12] = { uint32_t reset_vec[12] = {
s->msel, /* MSEL pin state */ s->msel, /* MSEL pin state */

View File

@ -40,6 +40,8 @@
#include "sysemu/device_tree.h" #include "sysemu/device_tree.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include <libfdt.h>
static const MemMapEntry spike_memmap[] = { static const MemMapEntry spike_memmap[] = {
[SPIKE_MROM] = { 0x1000, 0xf000 }, [SPIKE_MROM] = { 0x1000, 0xf000 },
[SPIKE_HTIF] = { 0x1000000, 0x1000 }, [SPIKE_HTIF] = { 0x1000000, 0x1000 },
@ -304,6 +306,10 @@ static void spike_board_init(MachineState *machine)
/* Compute the fdt load address in dram */ /* Compute the fdt load address in dram */
fdt_load_addr = riscv_load_fdt(memmap[SPIKE_DRAM].base, fdt_load_addr = riscv_load_fdt(memmap[SPIKE_DRAM].base,
machine->ram_size, s->fdt); machine->ram_size, s->fdt);
/* Set machine->fdt for 'dumpdtb' QMP/HMP command */
machine->fdt = s->fdt;
/* load the reset vector */ /* load the reset vector */
riscv_setup_rom_reset_vec(machine, &s->soc[0], memmap[SPIKE_DRAM].base, riscv_setup_rom_reset_vec(machine, &s->soc[0], memmap[SPIKE_DRAM].base,
memmap[SPIKE_MROM].base, memmap[SPIKE_MROM].base,

View File

@ -941,7 +941,7 @@ static void esp_soft_reset(ESPState *s)
static void esp_bus_reset(ESPState *s) static void esp_bus_reset(ESPState *s)
{ {
qbus_reset_all(BUS(&s->bus)); bus_cold_reset(BUS(&s->bus));
} }
static void parent_esp_reset(ESPState *s, int irq, int level) static void parent_esp_reset(ESPState *s, int irq, int level)

View File

@ -1868,7 +1868,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
} }
if (val & LSI_SCNTL1_RST) { if (val & LSI_SCNTL1_RST) {
if (!(s->sstat0 & LSI_SSTAT0_RST)) { if (!(s->sstat0 & LSI_SSTAT0_RST)) {
qbus_reset_all(BUS(&s->bus)); bus_cold_reset(BUS(&s->bus));
s->sstat0 |= LSI_SSTAT0_RST; s->sstat0 |= LSI_SSTAT0_RST;
lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0); lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0);
} }
@ -1926,7 +1926,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
lsi_execute_script(s); lsi_execute_script(s);
} }
if (val & LSI_ISTAT0_SRST) { if (val & LSI_ISTAT0_SRST) {
qdev_reset_all(DEVICE(s)); device_cold_reset(DEVICE(s));
} }
break; break;
case 0x16: /* MBOX0 */ case 0x16: /* MBOX0 */

View File

@ -1484,7 +1484,7 @@ static int megasas_cluster_reset_ld(MegasasState *s, MegasasCmd *cmd)
MegasasCmd *tmp_cmd = &s->frames[i]; MegasasCmd *tmp_cmd = &s->frames[i];
if (tmp_cmd->req && tmp_cmd->req->dev->id == target_id) { if (tmp_cmd->req && tmp_cmd->req->dev->id == target_id) {
SCSIDevice *d = tmp_cmd->req->dev; SCSIDevice *d = tmp_cmd->req->dev;
qdev_reset_all(&d->qdev); device_cold_reset(&d->qdev);
} }
} }
return MFI_STAT_OK; return MFI_STAT_OK;

View File

@ -522,7 +522,7 @@ reply_maybe_async:
reply.ResponseCode = MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN; reply.ResponseCode = MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN;
goto out; goto out;
} }
qdev_reset_all(&sdev->qdev); device_cold_reset(&sdev->qdev);
break; break;
case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET: case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
@ -538,13 +538,13 @@ reply_maybe_async:
QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
sdev = SCSI_DEVICE(kid->child); sdev = SCSI_DEVICE(kid->child);
if (sdev->channel == 0 && sdev->id == req->TargetID) { if (sdev->channel == 0 && sdev->id == req->TargetID) {
qdev_reset_all(kid->child); device_cold_reset(kid->child);
} }
} }
break; break;
case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS: case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
qbus_reset_all(BUS(&s->bus)); bus_cold_reset(BUS(&s->bus));
break; break;
default: default:
@ -807,7 +807,7 @@ static void mptsas_soft_reset(MPTSASState *s)
s->intr_mask = MPI_HIM_DIM | MPI_HIM_RIM; s->intr_mask = MPI_HIM_DIM | MPI_HIM_RIM;
mptsas_update_interrupt(s); mptsas_update_interrupt(s);
qbus_reset_all(BUS(&s->bus)); bus_cold_reset(BUS(&s->bus));
s->intr_status = 0; s->intr_status = 0;
s->intr_mask = save_mask; s->intr_mask = save_mask;

View File

@ -1616,6 +1616,24 @@ static int scsi_ua_precedence(SCSISense sense)
return (sense.asc << 8) | sense.ascq; return (sense.asc << 8) | sense.ascq;
} }
void scsi_bus_set_ua(SCSIBus *bus, SCSISense sense)
{
int prec1, prec2;
if (sense.key != UNIT_ATTENTION) {
return;
}
/*
* Override a pre-existing unit attention condition, except for a more
* important reset condition.
*/
prec1 = scsi_ua_precedence(bus->unit_attention);
prec2 = scsi_ua_precedence(sense);
if (prec2 < prec1) {
bus->unit_attention = sense;
}
}
void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense) void scsi_device_set_ua(SCSIDevice *sdev, SCSISense sense)
{ {
int prec1, prec2; int prec1, prec2;

View File

@ -865,7 +865,7 @@ static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req)
break; break;
} }
qdev_reset_all(&d->qdev); device_cold_reset(&d->qdev);
break; break;
case SRP_TSK_ABORT_TASK_SET: case SRP_TSK_ABORT_TASK_SET:

View File

@ -365,7 +365,7 @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
goto incorrect_lun; goto incorrect_lun;
} }
s->resetting++; s->resetting++;
qdev_reset_all(&d->qdev); device_cold_reset(&d->qdev);
s->resetting--; s->resetting--;
break; break;
@ -417,7 +417,7 @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
QTAILQ_FOREACH_RCU(kid, &s->bus.qbus.children, sibling) { QTAILQ_FOREACH_RCU(kid, &s->bus.qbus.children, sibling) {
SCSIDevice *d1 = SCSI_DEVICE(kid->child); SCSIDevice *d1 = SCSI_DEVICE(kid->child);
if (d1->channel == 0 && d1->id == target) { if (d1->channel == 0 && d1->id == target) {
qdev_reset_all(&d1->qdev); device_cold_reset(&d1->qdev);
} }
} }
rcu_read_unlock(); rcu_read_unlock();
@ -831,7 +831,7 @@ static void virtio_scsi_reset(VirtIODevice *vdev)
assert(!s->dataplane_started); assert(!s->dataplane_started);
s->resetting++; s->resetting++;
qbus_reset_all(BUS(&s->bus)); bus_cold_reset(BUS(&s->bus));
s->resetting--; s->resetting--;
vs->sense_size = VIRTIO_SCSI_SENSE_DEFAULT_SIZE; vs->sense_size = VIRTIO_SCSI_SENSE_DEFAULT_SIZE;
@ -956,6 +956,7 @@ static void virtio_scsi_hotplug(HotplugHandler *hotplug_dev, DeviceState *dev,
virtio_scsi_push_event(s, sd, virtio_scsi_push_event(s, sd,
VIRTIO_SCSI_T_TRANSPORT_RESET, VIRTIO_SCSI_T_TRANSPORT_RESET,
VIRTIO_SCSI_EVT_RESET_RESCAN); VIRTIO_SCSI_EVT_RESET_RESCAN);
scsi_bus_set_ua(&s->bus, SENSE_CODE(REPORTED_LUNS_CHANGED));
virtio_scsi_release(s); virtio_scsi_release(s);
} }
} }
@ -973,6 +974,7 @@ static void virtio_scsi_hotunplug(HotplugHandler *hotplug_dev, DeviceState *dev,
virtio_scsi_push_event(s, sd, virtio_scsi_push_event(s, sd,
VIRTIO_SCSI_T_TRANSPORT_RESET, VIRTIO_SCSI_T_TRANSPORT_RESET,
VIRTIO_SCSI_EVT_RESET_REMOVED); VIRTIO_SCSI_EVT_RESET_REMOVED);
scsi_bus_set_ua(&s->bus, SENSE_CODE(REPORTED_LUNS_CHANGED));
virtio_scsi_release(s); virtio_scsi_release(s);
} }

View File

@ -445,7 +445,7 @@ static void
pvscsi_reset_adapter(PVSCSIState *s) pvscsi_reset_adapter(PVSCSIState *s)
{ {
s->resetting++; s->resetting++;
qbus_reset_all(BUS(&s->bus)); bus_cold_reset(BUS(&s->bus));
s->resetting--; s->resetting--;
pvscsi_process_completion_queue(s); pvscsi_process_completion_queue(s);
assert(QTAILQ_EMPTY(&s->pending_queue)); assert(QTAILQ_EMPTY(&s->pending_queue));
@ -880,7 +880,7 @@ pvscsi_on_cmd_reset_device(PVSCSIState *s)
if (sdev != NULL) { if (sdev != NULL) {
s->resetting++; s->resetting++;
device_legacy_reset(&sdev->qdev); device_cold_reset(&sdev->qdev);
s->resetting--; s->resetting--;
return PVSCSI_COMMAND_PROCESSING_SUCCEEDED; return PVSCSI_COMMAND_PROCESSING_SUCCEEDED;
} }
@ -894,7 +894,7 @@ pvscsi_on_cmd_reset_bus(PVSCSIState *s)
trace_pvscsi_on_cmd_arrived("PVSCSI_CMD_RESET_BUS"); trace_pvscsi_on_cmd_arrived("PVSCSI_CMD_RESET_BUS");
s->resetting++; s->resetting++;
qbus_reset_all(BUS(&s->bus)); bus_cold_reset(BUS(&s->bus));
s->resetting--; s->resetting--;
return PVSCSI_COMMAND_PROCESSING_SUCCEEDED; return PVSCSI_COMMAND_PROCESSING_SUCCEEDED;
} }

View File

@ -29,16 +29,17 @@
#include "exec/memory.h" #include "exec/memory.h"
#include "hw/sysbus.h" #include "hw/sysbus.h"
void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks, typedef struct {
MemoryRegion ram_memories[], MemoryRegion ram;
hwaddr ram_bases[], hwaddr ram_sizes[], MemoryRegion container; /* used for clipping */
const ram_addr_t sdram_bank_sizes[]); hwaddr base;
hwaddr size;
uint32_t bcr;
} Ppc4xxSdramBank;
void ppc4xx_sdram_init (CPUPPCState *env, qemu_irq irq, int nbanks, void ppc4xx_sdram_banks(MemoryRegion *ram, int nr_banks,
MemoryRegion ram_memories[], Ppc4xxSdramBank ram_banks[],
hwaddr *ram_bases, const ram_addr_t sdram_bank_sizes[]);
hwaddr *ram_sizes,
int do_init);
#define TYPE_PPC4xx_PCI_HOST_BRIDGE "ppc4xx-pcihost" #define TYPE_PPC4xx_PCI_HOST_BRIDGE "ppc4xx-pcihost"
@ -109,4 +110,50 @@ struct Ppc4xxEbcState {
uint32_t cfg; uint32_t cfg;
}; };
/* SDRAM DDR controller */
#define SDR0_DDR0_DDRM_ENCODE(n) ((((unsigned long)(n)) & 0x03) << 29)
#define SDR0_DDR0_DDRM_DDR1 0x20000000
#define SDR0_DDR0_DDRM_DDR2 0x40000000
#define TYPE_PPC4xx_SDRAM_DDR "ppc4xx-sdram-ddr"
OBJECT_DECLARE_SIMPLE_TYPE(Ppc4xxSdramDdrState, PPC4xx_SDRAM_DDR);
struct Ppc4xxSdramDdrState {
Ppc4xxDcrDeviceState parent_obj;
MemoryRegion *dram_mr;
uint32_t nbanks; /* Banks to use from 4, e.g. when board has less slots */
Ppc4xxSdramBank bank[4];
qemu_irq irq;
uint32_t addr;
uint32_t besr0;
uint32_t besr1;
uint32_t bear;
uint32_t cfg;
uint32_t status;
uint32_t rtr;
uint32_t pmit;
uint32_t tr;
uint32_t ecccfg;
uint32_t eccesr;
};
void ppc4xx_sdram_ddr_enable(Ppc4xxSdramDdrState *s);
/* SDRAM DDR2 controller */
#define TYPE_PPC4xx_SDRAM_DDR2 "ppc4xx-sdram-ddr2"
OBJECT_DECLARE_SIMPLE_TYPE(Ppc4xxSdramDdr2State, PPC4xx_SDRAM_DDR2);
struct Ppc4xxSdramDdr2State {
Ppc4xxDcrDeviceState parent_obj;
MemoryRegion *dram_mr;
uint32_t nbanks; /* Banks to use from 4, e.g. when board has less slots */
Ppc4xxSdramBank bank[4];
uint32_t addr;
uint32_t mcopt2;
};
void ppc4xx_sdram_ddr2_enable(Ppc4xxSdramDdr2State *s);
#endif /* PPC4XX_H */ #endif /* PPC4XX_H */

View File

@ -186,6 +186,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk,
BlockdevOnError rerror, BlockdevOnError rerror,
BlockdevOnError werror, BlockdevOnError werror,
const char *serial, Error **errp); const char *serial, Error **errp);
void scsi_bus_set_ua(SCSIBus *bus, SCSISense sense);
void scsi_bus_legacy_handle_cmdline(SCSIBus *bus); void scsi_bus_legacy_handle_cmdline(SCSIBus *bus);
void scsi_legacy_handle_cmdline(void); void scsi_legacy_handle_cmdline(void);

View File

@ -136,6 +136,7 @@ int qemu_fdt_add_path(void *fdt, const char *path);
} while (0) } while (0)
void qemu_fdt_dumpdtb(void *fdt, int size); void qemu_fdt_dumpdtb(void *fdt, int size);
void hmp_dumpdtb(Monitor *mon, const QDict *qdict);
/** /**
* qemu_fdt_setprop_sized_cells_from_array: * qemu_fdt_setprop_sized_cells_from_array:

View File

@ -2262,7 +2262,8 @@ struct target_statfs64 {
}; };
#elif (defined(TARGET_PPC64) || defined(TARGET_X86_64) || \ #elif (defined(TARGET_PPC64) || defined(TARGET_X86_64) || \
defined(TARGET_SPARC64) || defined(TARGET_AARCH64) || \ defined(TARGET_SPARC64) || defined(TARGET_AARCH64) || \
defined(TARGET_RISCV)) && !defined(TARGET_ABI32) defined(TARGET_RISCV) || defined(TARGET_LOONGARCH64)) && \
!defined(TARGET_ABI32)
struct target_statfs { struct target_statfs {
abi_long f_type; abi_long f_type;
abi_long f_bsize; abi_long f_bsize;

View File

@ -49,6 +49,7 @@
#include "sysemu/blockdev.h" #include "sysemu/blockdev.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "sysemu/tpm.h" #include "sysemu/tpm.h"
#include "sysemu/device_tree.h"
#include "qapi/qmp/qdict.h" #include "qapi/qmp/qdict.h"
#include "qapi/qmp/qerror.h" #include "qapi/qmp/qerror.h"
#include "qapi/qmp/qstring.h" #include "qapi/qmp/qstring.h"

View File

@ -1664,3 +1664,21 @@
'*size': 'size', '*size': 'size',
'*max-size': 'size', '*max-size': 'size',
'*slots': 'uint64' } } '*slots': 'uint64' } }
##
# @dumpdtb:
#
# Save the FDT in dtb format.
#
# @filename: name of the dtb file to be created
#
# Since: 7.2
#
# Example:
# {"execute": "dumpdtb"}
# "arguments": { "filename": "fdt.dtb" } }
#
##
{ 'command': 'dumpdtb',
'data': { 'filename': 'str' },
'if': 'CONFIG_FDT' }

View File

@ -26,6 +26,9 @@
#include "hw/loader.h" #include "hw/loader.h"
#include "hw/boards.h" #include "hw/boards.h"
#include "qemu/config-file.h" #include "qemu/config-file.h"
#include "qapi/qapi-commands-machine.h"
#include "qapi/qmp/qdict.h"
#include "monitor/hmp.h"
#include <libfdt.h> #include <libfdt.h>
@ -643,3 +646,37 @@ out:
g_free(propcells); g_free(propcells);
return ret; return ret;
} }
void qmp_dumpdtb(const char *filename, Error **errp)
{
g_autoptr(GError) err = NULL;
uint32_t size;
if (!current_machine->fdt) {
error_setg(errp, "This machine doesn't have a FDT");
return;
}
size = fdt_totalsize(current_machine->fdt);
g_assert(size > 0);
if (!g_file_set_contents(filename, current_machine->fdt, size, &err)) {
error_setg(errp, "Error saving FDT to file %s: %s",
filename, err->message);
}
}
void hmp_dumpdtb(Monitor *mon, const QDict *qdict)
{
const char *filename = qdict_get_str(qdict, "filename");
Error *local_err = NULL;
qmp_dumpdtb(filename, &local_err);
if (hmp_handle_error(mon, local_err)) {
return;
}
info_report("dtb dumped to %s", filename);
}

View File

@ -23,7 +23,7 @@
# define TARGET_VIRT_ADDR_SPACE_BITS 32 # define TARGET_VIRT_ADDR_SPACE_BITS 32
#endif #endif
#define TARGET_PAGE_BITS 12 #define TARGET_PAGE_BITS 12
#define NB_MMU_MODES 3 #define NB_MMU_MODES 5
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
# define TARGET_TB_PCREL 1 # define TARGET_TB_PCREL 1

View File

@ -625,12 +625,12 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_POPCNT | \ CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_POPCNT | \
CPUID_EXT_XSAVE | /* CPUID_EXT_OSXSAVE is dynamic */ \ CPUID_EXT_XSAVE | /* CPUID_EXT_OSXSAVE is dynamic */ \
CPUID_EXT_MOVBE | CPUID_EXT_AES | CPUID_EXT_HYPERVISOR | \ CPUID_EXT_MOVBE | CPUID_EXT_AES | CPUID_EXT_HYPERVISOR | \
CPUID_EXT_RDRAND) CPUID_EXT_RDRAND | CPUID_EXT_AVX)
/* missing: /* missing:
CPUID_EXT_DTES64, CPUID_EXT_DSCPL, CPUID_EXT_VMX, CPUID_EXT_SMX, CPUID_EXT_DTES64, CPUID_EXT_DSCPL, CPUID_EXT_VMX, CPUID_EXT_SMX,
CPUID_EXT_EST, CPUID_EXT_TM2, CPUID_EXT_CID, CPUID_EXT_FMA, CPUID_EXT_EST, CPUID_EXT_TM2, CPUID_EXT_CID, CPUID_EXT_FMA,
CPUID_EXT_XTPR, CPUID_EXT_PDCM, CPUID_EXT_PCID, CPUID_EXT_DCA, CPUID_EXT_XTPR, CPUID_EXT_PDCM, CPUID_EXT_PCID, CPUID_EXT_DCA,
CPUID_EXT_X2APIC, CPUID_EXT_TSC_DEADLINE_TIMER, CPUID_EXT_AVX, CPUID_EXT_X2APIC, CPUID_EXT_TSC_DEADLINE_TIMER,
CPUID_EXT_F16C */ CPUID_EXT_F16C */
#ifdef TARGET_X86_64 #ifdef TARGET_X86_64
@ -653,14 +653,14 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | \ CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | \
CPUID_7_0_EBX_PCOMMIT | CPUID_7_0_EBX_CLFLUSHOPT | \ CPUID_7_0_EBX_PCOMMIT | CPUID_7_0_EBX_CLFLUSHOPT | \
CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_FSGSBASE | \ CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_FSGSBASE | \
CPUID_7_0_EBX_ERMS) CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_AVX2)
/* missing: /* missing:
CPUID_7_0_EBX_HLE, CPUID_7_0_EBX_AVX2, CPUID_7_0_EBX_HLE
CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM, CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM,
CPUID_7_0_EBX_RDSEED */ CPUID_7_0_EBX_RDSEED */
#define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | \ #define TCG_7_0_ECX_FEATURES (CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | \
/* CPUID_7_0_ECX_OSPKE is dynamic */ \ /* CPUID_7_0_ECX_OSPKE is dynamic */ \
CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS) CPUID_7_0_ECX_LA57 | CPUID_7_0_ECX_PKS | CPUID_7_0_ECX_VAES)
#define TCG_7_0_EDX_FEATURES 0 #define TCG_7_0_EDX_FEATURES 0
#define TCG_7_1_EAX_FEATURES 0 #define TCG_7_1_EAX_FEATURES 0
#define TCG_APM_FEATURES 0 #define TCG_APM_FEATURES 0
@ -6035,6 +6035,19 @@ static void x86_cpu_reset(DeviceState *dev)
#endif #endif
} }
void x86_cpu_after_reset(X86CPU *cpu)
{
#ifndef CONFIG_USER_ONLY
if (kvm_enabled()) {
kvm_arch_after_reset_vcpu(cpu);
}
if (cpu->apic_state) {
device_cold_reset(cpu->apic_state);
}
#endif
}
static void mce_init(X86CPU *cpu) static void mce_init(X86CPU *cpu)
{ {
CPUX86State *cenv = &cpu->env; CPUX86State *cenv = &cpu->env;

View File

@ -169,6 +169,7 @@ typedef enum X86Seg {
#define HF_MPX_EN_SHIFT 25 /* MPX Enabled (CR4+XCR0+BNDCFGx) */ #define HF_MPX_EN_SHIFT 25 /* MPX Enabled (CR4+XCR0+BNDCFGx) */
#define HF_MPX_IU_SHIFT 26 /* BND registers in-use */ #define HF_MPX_IU_SHIFT 26 /* BND registers in-use */
#define HF_UMIP_SHIFT 27 /* CR4.UMIP */ #define HF_UMIP_SHIFT 27 /* CR4.UMIP */
#define HF_AVX_EN_SHIFT 28 /* AVX Enabled (CR4+XCR0) */
#define HF_CPL_MASK (3 << HF_CPL_SHIFT) #define HF_CPL_MASK (3 << HF_CPL_SHIFT)
#define HF_INHIBIT_IRQ_MASK (1 << HF_INHIBIT_IRQ_SHIFT) #define HF_INHIBIT_IRQ_MASK (1 << HF_INHIBIT_IRQ_SHIFT)
@ -195,6 +196,7 @@ typedef enum X86Seg {
#define HF_MPX_EN_MASK (1 << HF_MPX_EN_SHIFT) #define HF_MPX_EN_MASK (1 << HF_MPX_EN_SHIFT)
#define HF_MPX_IU_MASK (1 << HF_MPX_IU_SHIFT) #define HF_MPX_IU_MASK (1 << HF_MPX_IU_SHIFT)
#define HF_UMIP_MASK (1 << HF_UMIP_SHIFT) #define HF_UMIP_MASK (1 << HF_UMIP_SHIFT)
#define HF_AVX_EN_MASK (1 << HF_AVX_EN_SHIFT)
/* hflags2 */ /* hflags2 */
@ -1233,18 +1235,34 @@ typedef struct SegmentCache {
uint32_t flags; uint32_t flags;
} SegmentCache; } SegmentCache;
#define MMREG_UNION(n, bits) \ typedef union MMXReg {
union n { \ uint8_t _b_MMXReg[64 / 8];
uint8_t _b_##n[(bits)/8]; \ uint16_t _w_MMXReg[64 / 16];
uint16_t _w_##n[(bits)/16]; \ uint32_t _l_MMXReg[64 / 32];
uint32_t _l_##n[(bits)/32]; \ uint64_t _q_MMXReg[64 / 64];
uint64_t _q_##n[(bits)/64]; \ float32 _s_MMXReg[64 / 32];
float32 _s_##n[(bits)/32]; \ float64 _d_MMXReg[64 / 64];
float64 _d_##n[(bits)/64]; \ } MMXReg;
}
typedef MMREG_UNION(ZMMReg, 512) ZMMReg; typedef union XMMReg {
typedef MMREG_UNION(MMXReg, 64) MMXReg; uint64_t _q_XMMReg[128 / 64];
} XMMReg;
typedef union YMMReg {
uint64_t _q_YMMReg[256 / 64];
XMMReg _x_YMMReg[256 / 128];
} YMMReg;
typedef union ZMMReg {
uint8_t _b_ZMMReg[512 / 8];
uint16_t _w_ZMMReg[512 / 16];
uint32_t _l_ZMMReg[512 / 32];
uint64_t _q_ZMMReg[512 / 64];
float32 _s_ZMMReg[512 / 32];
float64 _d_ZMMReg[512 / 64];
XMMReg _x_ZMMReg[512 / 128];
YMMReg _y_ZMMReg[512 / 256];
} ZMMReg;
typedef struct BNDReg { typedef struct BNDReg {
uint64_t lb; uint64_t lb;
@ -1267,6 +1285,13 @@ typedef struct BNDCSReg {
#define ZMM_S(n) _s_ZMMReg[15 - (n)] #define ZMM_S(n) _s_ZMMReg[15 - (n)]
#define ZMM_Q(n) _q_ZMMReg[7 - (n)] #define ZMM_Q(n) _q_ZMMReg[7 - (n)]
#define ZMM_D(n) _d_ZMMReg[7 - (n)] #define ZMM_D(n) _d_ZMMReg[7 - (n)]
#define ZMM_X(n) _x_ZMMReg[3 - (n)]
#define ZMM_Y(n) _y_ZMMReg[1 - (n)]
#define XMM_Q(n) _q_XMMReg[1 - (n)]
#define YMM_Q(n) _q_YMMReg[3 - (n)]
#define YMM_X(n) _x_YMMReg[1 - (n)]
#define MMX_B(n) _b_MMXReg[7 - (n)] #define MMX_B(n) _b_MMXReg[7 - (n)]
#define MMX_W(n) _w_MMXReg[3 - (n)] #define MMX_W(n) _w_MMXReg[3 - (n)]
@ -1279,6 +1304,13 @@ typedef struct BNDCSReg {
#define ZMM_S(n) _s_ZMMReg[n] #define ZMM_S(n) _s_ZMMReg[n]
#define ZMM_Q(n) _q_ZMMReg[n] #define ZMM_Q(n) _q_ZMMReg[n]
#define ZMM_D(n) _d_ZMMReg[n] #define ZMM_D(n) _d_ZMMReg[n]
#define ZMM_X(n) _x_ZMMReg[n]
#define ZMM_Y(n) _y_ZMMReg[n]
#define XMM_Q(n) _q_XMMReg[n]
#define YMM_Q(n) _q_YMMReg[n]
#define YMM_X(n) _x_YMMReg[n]
#define MMX_B(n) _b_MMXReg[n] #define MMX_B(n) _b_MMXReg[n]
#define MMX_W(n) _w_MMXReg[n] #define MMX_W(n) _w_MMXReg[n]
@ -1556,8 +1588,8 @@ typedef struct CPUArchState {
float_status mmx_status; /* for 3DNow! float ops */ float_status mmx_status; /* for 3DNow! float ops */
float_status sse_status; float_status sse_status;
uint32_t mxcsr; uint32_t mxcsr;
ZMMReg xmm_regs[CPU_NB_REGS == 8 ? 8 : 32]; ZMMReg xmm_regs[CPU_NB_REGS == 8 ? 8 : 32] QEMU_ALIGNED(16);
ZMMReg xmm_t0; ZMMReg xmm_t0 QEMU_ALIGNED(16);
MMXReg mmx_t0; MMXReg mmx_t0;
uint64_t opmask_regs[NB_OPMASK_REGS]; uint64_t opmask_regs[NB_OPMASK_REGS];
@ -2082,6 +2114,8 @@ typedef struct PropValue {
} PropValue; } PropValue;
void x86_cpu_apply_props(X86CPU *cpu, PropValue *props); void x86_cpu_apply_props(X86CPU *cpu, PropValue *props);
void x86_cpu_after_reset(X86CPU *cpu);
uint32_t cpu_x86_virtual_addr_width(CPUX86State *env); uint32_t cpu_x86_virtual_addr_width(CPUX86State *env);
/* cpu.c other functions (cpuid) */ /* cpu.c other functions (cpuid) */
@ -2094,6 +2128,7 @@ void host_cpuid(uint32_t function, uint32_t count,
/* helper.c */ /* helper.c */
void x86_cpu_set_a20(X86CPU *cpu, int a20_state); void x86_cpu_set_a20(X86CPU *cpu, int a20_state);
void cpu_sync_avx_hflag(CPUX86State *env);
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
static inline int x86_asidx_from_attrs(CPUState *cs, MemTxAttrs attrs) static inline int x86_asidx_from_attrs(CPUState *cs, MemTxAttrs attrs)
@ -2147,6 +2182,9 @@ uint64_t cpu_get_tsc(CPUX86State *env);
#define MMU_KSMAP_IDX 0 #define MMU_KSMAP_IDX 0
#define MMU_USER_IDX 1 #define MMU_USER_IDX 1
#define MMU_KNOSMAP_IDX 2 #define MMU_KNOSMAP_IDX 2
#define MMU_NESTED_IDX 3
#define MMU_PHYS_IDX 4
static inline int cpu_mmu_index(CPUX86State *env, bool ifetch) static inline int cpu_mmu_index(CPUX86State *env, bool ifetch)
{ {
return (env->hflags & HF_CPL_MASK) == 3 ? MMU_USER_IDX : return (env->hflags & HF_CPL_MASK) == 3 ? MMU_USER_IDX :
@ -2382,8 +2420,6 @@ static inline bool ctl_has_irq(CPUX86State *env)
return (env->int_ctl & V_IRQ_MASK) && (int_prio >= tpr); return (env->int_ctl & V_IRQ_MASK) && (int_prio >= tpr);
} }
hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type,
int *prot);
#if defined(TARGET_X86_64) && \ #if defined(TARGET_X86_64) && \
defined(CONFIG_USER_ONLY) && \ defined(CONFIG_USER_ONLY) && \
defined(CONFIG_LINUX) defined(CONFIG_LINUX)

View File

@ -29,6 +29,17 @@
#endif #endif
#include "qemu/log.h" #include "qemu/log.h"
void cpu_sync_avx_hflag(CPUX86State *env)
{
if ((env->cr[4] & CR4_OSXSAVE_MASK)
&& (env->xcr0 & (XSTATE_SSE_MASK | XSTATE_YMM_MASK))
== (XSTATE_SSE_MASK | XSTATE_YMM_MASK)) {
env->hflags |= HF_AVX_EN_MASK;
} else{
env->hflags &= ~HF_AVX_EN_MASK;
}
}
void cpu_sync_bndcs_hflags(CPUX86State *env) void cpu_sync_bndcs_hflags(CPUX86State *env)
{ {
uint32_t hflags = env->hflags; uint32_t hflags = env->hflags;
@ -209,6 +220,7 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
env->hflags = hflags; env->hflags = hflags;
cpu_sync_bndcs_hflags(env); cpu_sync_bndcs_hflags(env);
cpu_sync_avx_hflag(env);
} }
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)

View File

@ -212,12 +212,13 @@ DEF_HELPER_2(ldmxcsr, void, env, i32)
DEF_HELPER_1(update_mxcsr, void, env) DEF_HELPER_1(update_mxcsr, void, env)
DEF_HELPER_1(enter_mmx, void, env) DEF_HELPER_1(enter_mmx, void, env)
DEF_HELPER_1(emms, void, env) DEF_HELPER_1(emms, void, env)
DEF_HELPER_3(movq, void, env, ptr, ptr)
#define SHIFT 0 #define SHIFT 0
#include "ops_sse_header.h" #include "ops_sse_header.h"
#define SHIFT 1 #define SHIFT 1
#include "ops_sse_header.h" #include "ops_sse_header.h"
#define SHIFT 2
#include "ops_sse_header.h"
DEF_HELPER_3(rclb, tl, env, tl, tl) DEF_HELPER_3(rclb, tl, env, tl, tl)
DEF_HELPER_3(rclw, tl, env, tl, tl) DEF_HELPER_3(rclw, tl, env, tl, tl)

View File

@ -23,6 +23,10 @@ int hyperv_x86_synic_add(X86CPU *cpu)
return 0; return 0;
} }
/*
* All devices possibly using SynIC have to be reset before calling this to let
* them remove their SINT routes first.
*/
void hyperv_x86_synic_reset(X86CPU *cpu) void hyperv_x86_synic_reset(X86CPU *cpu)
{ {
hyperv_synic_reset(CPU(cpu)); hyperv_synic_reset(CPU(cpu));

View File

@ -2203,14 +2203,6 @@ void kvm_arch_reset_vcpu(X86CPU *cpu)
env->mp_state = KVM_MP_STATE_RUNNABLE; env->mp_state = KVM_MP_STATE_RUNNABLE;
} }
if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNIC)) {
int i;
for (i = 0; i < ARRAY_SIZE(env->msr_hv_synic_sint); i++) {
env->msr_hv_synic_sint[i] = HV_SINT_MASKED;
}
hyperv_x86_synic_reset(cpu);
}
/* enabled by default */ /* enabled by default */
env->poll_control_msr = 1; env->poll_control_msr = 1;
@ -2219,6 +2211,24 @@ void kvm_arch_reset_vcpu(X86CPU *cpu)
sev_es_set_reset_vector(CPU(cpu)); sev_es_set_reset_vector(CPU(cpu));
} }
void kvm_arch_after_reset_vcpu(X86CPU *cpu)
{
CPUX86State *env = &cpu->env;
int i;
/*
* Reset SynIC after all other devices have been reset to let them remove
* their SINT routes first.
*/
if (hyperv_feat_enabled(cpu, HYPERV_FEAT_SYNIC)) {
for (i = 0; i < ARRAY_SIZE(env->msr_hv_synic_sint); i++) {
env->msr_hv_synic_sint[i] = HV_SINT_MASKED;
}
hyperv_x86_synic_reset(cpu);
}
}
void kvm_arch_do_init_vcpu(X86CPU *cpu) void kvm_arch_do_init_vcpu(X86CPU *cpu)
{ {
CPUX86State *env = &cpu->env; CPUX86State *env = &cpu->env;

View File

@ -38,6 +38,7 @@ bool kvm_has_adjust_clock_stable(void);
bool kvm_has_exception_payload(void); bool kvm_has_exception_payload(void);
void kvm_synchronize_all_tsc(void); void kvm_synchronize_all_tsc(void);
void kvm_arch_reset_vcpu(X86CPU *cs); void kvm_arch_reset_vcpu(X86CPU *cs);
void kvm_arch_after_reset_vcpu(X86CPU *cpu);
void kvm_arch_do_init_vcpu(X86CPU *cs); void kvm_arch_do_init_vcpu(X86CPU *cs);
void kvm_put_apicbase(X86CPU *cpu, uint64_t value); void kvm_put_apicbase(X86CPU *cpu, uint64_t value);

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,11 @@
#define SUFFIX _mmx #define SUFFIX _mmx
#else #else
#define Reg ZMMReg #define Reg ZMMReg
#if SHIFT == 1
#define SUFFIX _xmm #define SUFFIX _xmm
#else
#define SUFFIX _ymm
#endif
#endif #endif
#define dh_alias_Reg ptr #define dh_alias_Reg ptr
@ -34,74 +38,34 @@
#define dh_typecode_ZMMReg dh_typecode_ptr #define dh_typecode_ZMMReg dh_typecode_ptr
#define dh_typecode_MMXReg dh_typecode_ptr #define dh_typecode_MMXReg dh_typecode_ptr
DEF_HELPER_3(glue(psrlw, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(psrlw, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(psraw, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(psraw, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(psllw, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(psllw, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(psrld, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(psrld, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(psrad, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(psrad, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(pslld, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(pslld, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(psrlq, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(psrlq, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(psllq, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(psllq, SUFFIX), void, env, Reg, Reg, Reg)
#if SHIFT == 1 #if SHIFT >= 1
DEF_HELPER_3(glue(psrldq, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(psrldq, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(pslldq, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(pslldq, SUFFIX), void, env, Reg, Reg, Reg)
#endif #endif
#define SSE_HELPER_B(name, F)\ #define SSE_HELPER_B(name, F)\
DEF_HELPER_3(glue(name, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(name, SUFFIX), void, env, Reg, Reg, Reg)
#define SSE_HELPER_W(name, F)\ #define SSE_HELPER_W(name, F)\
DEF_HELPER_3(glue(name, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(name, SUFFIX), void, env, Reg, Reg, Reg)
#define SSE_HELPER_L(name, F)\ #define SSE_HELPER_L(name, F)\
DEF_HELPER_3(glue(name, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(name, SUFFIX), void, env, Reg, Reg, Reg)
#define SSE_HELPER_Q(name, F)\ #define SSE_HELPER_Q(name, F)\
DEF_HELPER_3(glue(name, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(name, SUFFIX), void, env, Reg, Reg, Reg)
SSE_HELPER_B(paddb, FADD)
SSE_HELPER_W(paddw, FADD)
SSE_HELPER_L(paddl, FADD)
SSE_HELPER_Q(paddq, FADD)
SSE_HELPER_B(psubb, FSUB)
SSE_HELPER_W(psubw, FSUB)
SSE_HELPER_L(psubl, FSUB)
SSE_HELPER_Q(psubq, FSUB)
SSE_HELPER_B(paddusb, FADDUB)
SSE_HELPER_B(paddsb, FADDSB)
SSE_HELPER_B(psubusb, FSUBUB)
SSE_HELPER_B(psubsb, FSUBSB)
SSE_HELPER_W(paddusw, FADDUW)
SSE_HELPER_W(paddsw, FADDSW)
SSE_HELPER_W(psubusw, FSUBUW)
SSE_HELPER_W(psubsw, FSUBSW)
SSE_HELPER_B(pminub, FMINUB)
SSE_HELPER_B(pmaxub, FMAXUB)
SSE_HELPER_W(pminsw, FMINSW)
SSE_HELPER_W(pmaxsw, FMAXSW)
SSE_HELPER_Q(pand, FAND)
SSE_HELPER_Q(pandn, FANDN)
SSE_HELPER_Q(por, FOR)
SSE_HELPER_Q(pxor, FXOR)
SSE_HELPER_B(pcmpgtb, FCMPGTB)
SSE_HELPER_W(pcmpgtw, FCMPGTW)
SSE_HELPER_L(pcmpgtl, FCMPGTL)
SSE_HELPER_B(pcmpeqb, FCMPEQ)
SSE_HELPER_W(pcmpeqw, FCMPEQ)
SSE_HELPER_L(pcmpeql, FCMPEQ)
SSE_HELPER_W(pmullw, FMULLW)
#if SHIFT == 0 #if SHIFT == 0
SSE_HELPER_W(pmulhrw, FMULHRW) DEF_HELPER_3(glue(pmulhrw, SUFFIX), void, env, Reg, Reg)
#endif #endif
SSE_HELPER_W(pmulhuw, FMULHUW) SSE_HELPER_W(pmulhuw, FMULHUW)
SSE_HELPER_W(pmulhw, FMULHW) SSE_HELPER_W(pmulhw, FMULHW)
@ -109,51 +73,74 @@ SSE_HELPER_W(pmulhw, FMULHW)
SSE_HELPER_B(pavgb, FAVG) SSE_HELPER_B(pavgb, FAVG)
SSE_HELPER_W(pavgw, FAVG) SSE_HELPER_W(pavgw, FAVG)
DEF_HELPER_3(glue(pmuludq, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(pmuludq, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(pmaddwd, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(pmaddwd, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(psadbw, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(psadbw, SUFFIX), void, env, Reg, Reg, Reg)
#if SHIFT < 2
DEF_HELPER_4(glue(maskmov, SUFFIX), void, env, Reg, Reg, tl) DEF_HELPER_4(glue(maskmov, SUFFIX), void, env, Reg, Reg, tl)
DEF_HELPER_2(glue(movl_mm_T0, SUFFIX), void, Reg, i32)
#ifdef TARGET_X86_64
DEF_HELPER_2(glue(movq_mm_T0, SUFFIX), void, Reg, i64)
#endif #endif
#if SHIFT == 0 #if SHIFT == 0
DEF_HELPER_3(glue(pshufw, SUFFIX), void, Reg, Reg, int) DEF_HELPER_3(glue(pshufw, SUFFIX), void, Reg, Reg, int)
#else #else
DEF_HELPER_3(glue(shufps, SUFFIX), void, Reg, Reg, int)
DEF_HELPER_3(glue(shufpd, SUFFIX), void, Reg, Reg, int)
DEF_HELPER_3(glue(pshufd, SUFFIX), void, Reg, Reg, int) DEF_HELPER_3(glue(pshufd, SUFFIX), void, Reg, Reg, int)
DEF_HELPER_3(glue(pshuflw, SUFFIX), void, Reg, Reg, int) DEF_HELPER_3(glue(pshuflw, SUFFIX), void, Reg, Reg, int)
DEF_HELPER_3(glue(pshufhw, SUFFIX), void, Reg, Reg, int) DEF_HELPER_3(glue(pshufhw, SUFFIX), void, Reg, Reg, int)
#endif #endif
#if SHIFT == 1 #if SHIFT >= 1
/* FPU ops */ /* FPU ops */
/* XXX: not accurate */ /* XXX: not accurate */
#define SSE_HELPER_S(name, F) \ #define SSE_HELPER_P4(name) \
DEF_HELPER_4(glue(name ## ps, SUFFIX), void, env, Reg, Reg, Reg) \
DEF_HELPER_4(glue(name ## pd, SUFFIX), void, env, Reg, Reg, Reg)
#define SSE_HELPER_P3(name, ...) \
DEF_HELPER_3(glue(name ## ps, SUFFIX), void, env, Reg, Reg) \ DEF_HELPER_3(glue(name ## ps, SUFFIX), void, env, Reg, Reg) \
DEF_HELPER_3(name ## ss, void, env, Reg, Reg) \ DEF_HELPER_3(glue(name ## pd, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(name ## pd, SUFFIX), void, env, Reg, Reg) \
DEF_HELPER_3(name ## sd, void, env, Reg, Reg)
SSE_HELPER_S(add, FPU_ADD) #if SHIFT == 1
SSE_HELPER_S(sub, FPU_SUB) #define SSE_HELPER_S4(name) \
SSE_HELPER_S(mul, FPU_MUL) SSE_HELPER_P4(name) \
SSE_HELPER_S(div, FPU_DIV) DEF_HELPER_4(name ## ss, void, env, Reg, Reg, Reg) \
SSE_HELPER_S(min, FPU_MIN) DEF_HELPER_4(name ## sd, void, env, Reg, Reg, Reg)
SSE_HELPER_S(max, FPU_MAX) #define SSE_HELPER_S3(name) \
SSE_HELPER_S(sqrt, FPU_SQRT) SSE_HELPER_P3(name) \
DEF_HELPER_4(name ## ss, void, env, Reg, Reg, Reg) \
DEF_HELPER_4(name ## sd, void, env, Reg, Reg, Reg)
#else
#define SSE_HELPER_S4(name, ...) SSE_HELPER_P4(name)
#define SSE_HELPER_S3(name, ...) SSE_HELPER_P3(name)
#endif
DEF_HELPER_4(glue(shufps, SUFFIX), void, Reg, Reg, Reg, int)
DEF_HELPER_4(glue(shufpd, SUFFIX), void, Reg, Reg, Reg, int)
SSE_HELPER_S4(add)
SSE_HELPER_S4(sub)
SSE_HELPER_S4(mul)
SSE_HELPER_S4(div)
SSE_HELPER_S4(min)
SSE_HELPER_S4(max)
SSE_HELPER_S3(sqrt)
DEF_HELPER_3(glue(cvtps2pd, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(glue(cvtps2pd, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(cvtpd2ps, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(glue(cvtpd2ps, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(cvtss2sd, void, env, Reg, Reg)
DEF_HELPER_3(cvtsd2ss, void, env, Reg, Reg)
DEF_HELPER_3(glue(cvtdq2ps, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(glue(cvtdq2ps, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(cvtdq2pd, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(glue(cvtdq2pd, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(cvtps2dq, SUFFIX), void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(glue(cvtpd2dq, SUFFIX), void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(glue(cvttps2dq, SUFFIX), void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(glue(cvttpd2dq, SUFFIX), void, env, ZMMReg, ZMMReg)
#if SHIFT == 1
DEF_HELPER_4(cvtss2sd, void, env, Reg, Reg, Reg)
DEF_HELPER_4(cvtsd2ss, void, env, Reg, Reg, Reg)
DEF_HELPER_3(cvtpi2ps, void, env, ZMMReg, MMXReg) DEF_HELPER_3(cvtpi2ps, void, env, ZMMReg, MMXReg)
DEF_HELPER_3(cvtpi2pd, void, env, ZMMReg, MMXReg) DEF_HELPER_3(cvtpi2pd, void, env, ZMMReg, MMXReg)
DEF_HELPER_3(cvtsi2ss, void, env, ZMMReg, i32) DEF_HELPER_3(cvtsi2ss, void, env, ZMMReg, i32)
@ -164,8 +151,6 @@ DEF_HELPER_3(cvtsq2ss, void, env, ZMMReg, i64)
DEF_HELPER_3(cvtsq2sd, void, env, ZMMReg, i64) DEF_HELPER_3(cvtsq2sd, void, env, ZMMReg, i64)
#endif #endif
DEF_HELPER_3(glue(cvtps2dq, SUFFIX), void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(glue(cvtpd2dq, SUFFIX), void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(cvtps2pi, void, env, MMXReg, ZMMReg) DEF_HELPER_3(cvtps2pi, void, env, MMXReg, ZMMReg)
DEF_HELPER_3(cvtpd2pi, void, env, MMXReg, ZMMReg) DEF_HELPER_3(cvtpd2pi, void, env, MMXReg, ZMMReg)
DEF_HELPER_2(cvtss2si, s32, env, ZMMReg) DEF_HELPER_2(cvtss2si, s32, env, ZMMReg)
@ -175,8 +160,6 @@ DEF_HELPER_2(cvtss2sq, s64, env, ZMMReg)
DEF_HELPER_2(cvtsd2sq, s64, env, ZMMReg) DEF_HELPER_2(cvtsd2sq, s64, env, ZMMReg)
#endif #endif
DEF_HELPER_3(glue(cvttps2dq, SUFFIX), void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(glue(cvttpd2dq, SUFFIX), void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(cvttps2pi, void, env, MMXReg, ZMMReg) DEF_HELPER_3(cvttps2pi, void, env, MMXReg, ZMMReg)
DEF_HELPER_3(cvttpd2pi, void, env, MMXReg, ZMMReg) DEF_HELPER_3(cvttpd2pi, void, env, MMXReg, ZMMReg)
DEF_HELPER_2(cvttss2si, s32, env, ZMMReg) DEF_HELPER_2(cvttss2si, s32, env, ZMMReg)
@ -185,27 +168,25 @@ DEF_HELPER_2(cvttsd2si, s32, env, ZMMReg)
DEF_HELPER_2(cvttss2sq, s64, env, ZMMReg) DEF_HELPER_2(cvttss2sq, s64, env, ZMMReg)
DEF_HELPER_2(cvttsd2sq, s64, env, ZMMReg) DEF_HELPER_2(cvttsd2sq, s64, env, ZMMReg)
#endif #endif
#endif
DEF_HELPER_3(glue(rsqrtps, SUFFIX), void, env, ZMMReg, ZMMReg) DEF_HELPER_3(glue(rsqrtps, SUFFIX), void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(rsqrtss, void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(glue(rcpps, SUFFIX), void, env, ZMMReg, ZMMReg) DEF_HELPER_3(glue(rcpps, SUFFIX), void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(rcpss, void, env, ZMMReg, ZMMReg)
#if SHIFT == 1
DEF_HELPER_4(rsqrtss, void, env, ZMMReg, ZMMReg, ZMMReg)
DEF_HELPER_4(rcpss, void, env, ZMMReg, ZMMReg, ZMMReg)
DEF_HELPER_3(extrq_r, void, env, ZMMReg, ZMMReg) DEF_HELPER_3(extrq_r, void, env, ZMMReg, ZMMReg)
DEF_HELPER_4(extrq_i, void, env, ZMMReg, int, int) DEF_HELPER_4(extrq_i, void, env, ZMMReg, int, int)
DEF_HELPER_3(insertq_r, void, env, ZMMReg, ZMMReg) DEF_HELPER_3(insertq_r, void, env, ZMMReg, ZMMReg)
DEF_HELPER_5(insertq_i, void, env, ZMMReg, ZMMReg, int, int) DEF_HELPER_5(insertq_i, void, env, ZMMReg, ZMMReg, int, int)
DEF_HELPER_3(glue(haddps, SUFFIX), void, env, ZMMReg, ZMMReg) #endif
DEF_HELPER_3(glue(haddpd, SUFFIX), void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(glue(hsubps, SUFFIX), void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(glue(hsubpd, SUFFIX), void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(glue(addsubps, SUFFIX), void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(glue(addsubpd, SUFFIX), void, env, ZMMReg, ZMMReg)
#define SSE_HELPER_CMP(name, F, C) \ SSE_HELPER_P4(hadd)
DEF_HELPER_3(glue(name ## ps, SUFFIX), void, env, Reg, Reg) \ SSE_HELPER_P4(hsub)
DEF_HELPER_3(name ## ss, void, env, Reg, Reg) \ SSE_HELPER_P4(addsub)
DEF_HELPER_3(glue(name ## pd, SUFFIX), void, env, Reg, Reg) \
DEF_HELPER_3(name ## sd, void, env, Reg, Reg) #define SSE_HELPER_CMP(name, F, C) SSE_HELPER_S4(name)
SSE_HELPER_CMP(cmpeq, FPU_CMPQ, FPU_EQ) SSE_HELPER_CMP(cmpeq, FPU_CMPQ, FPU_EQ)
SSE_HELPER_CMP(cmplt, FPU_CMPS, FPU_LT) SSE_HELPER_CMP(cmplt, FPU_CMPS, FPU_LT)
@ -216,29 +197,58 @@ SSE_HELPER_CMP(cmpnlt, FPU_CMPS, !FPU_LT)
SSE_HELPER_CMP(cmpnle, FPU_CMPS, !FPU_LE) SSE_HELPER_CMP(cmpnle, FPU_CMPS, !FPU_LE)
SSE_HELPER_CMP(cmpord, FPU_CMPQ, !FPU_UNORD) SSE_HELPER_CMP(cmpord, FPU_CMPQ, !FPU_UNORD)
SSE_HELPER_CMP(cmpequ, FPU_CMPQ, FPU_EQU)
SSE_HELPER_CMP(cmpnge, FPU_CMPS, !FPU_GE)
SSE_HELPER_CMP(cmpngt, FPU_CMPS, !FPU_GT)
SSE_HELPER_CMP(cmpfalse, FPU_CMPQ, FPU_FALSE)
SSE_HELPER_CMP(cmpnequ, FPU_CMPQ, !FPU_EQU)
SSE_HELPER_CMP(cmpge, FPU_CMPS, FPU_GE)
SSE_HELPER_CMP(cmpgt, FPU_CMPS, FPU_GT)
SSE_HELPER_CMP(cmptrue, FPU_CMPQ, !FPU_FALSE)
SSE_HELPER_CMP(cmpeqs, FPU_CMPS, FPU_EQ)
SSE_HELPER_CMP(cmpltq, FPU_CMPQ, FPU_LT)
SSE_HELPER_CMP(cmpleq, FPU_CMPQ, FPU_LE)
SSE_HELPER_CMP(cmpunords, FPU_CMPS, FPU_UNORD)
SSE_HELPER_CMP(cmpneqq, FPU_CMPS, !FPU_EQ)
SSE_HELPER_CMP(cmpnltq, FPU_CMPQ, !FPU_LT)
SSE_HELPER_CMP(cmpnleq, FPU_CMPQ, !FPU_LE)
SSE_HELPER_CMP(cmpords, FPU_CMPS, !FPU_UNORD)
SSE_HELPER_CMP(cmpequs, FPU_CMPS, FPU_EQU)
SSE_HELPER_CMP(cmpngeq, FPU_CMPQ, !FPU_GE)
SSE_HELPER_CMP(cmpngtq, FPU_CMPQ, !FPU_GT)
SSE_HELPER_CMP(cmpfalses, FPU_CMPS, FPU_FALSE)
SSE_HELPER_CMP(cmpnequs, FPU_CMPS, !FPU_EQU)
SSE_HELPER_CMP(cmpgeq, FPU_CMPQ, FPU_GE)
SSE_HELPER_CMP(cmpgtq, FPU_CMPQ, FPU_GT)
SSE_HELPER_CMP(cmptrues, FPU_CMPS, !FPU_FALSE)
#if SHIFT == 1
DEF_HELPER_3(ucomiss, void, env, Reg, Reg) DEF_HELPER_3(ucomiss, void, env, Reg, Reg)
DEF_HELPER_3(comiss, void, env, Reg, Reg) DEF_HELPER_3(comiss, void, env, Reg, Reg)
DEF_HELPER_3(ucomisd, void, env, Reg, Reg) DEF_HELPER_3(ucomisd, void, env, Reg, Reg)
DEF_HELPER_3(comisd, void, env, Reg, Reg) DEF_HELPER_3(comisd, void, env, Reg, Reg)
#endif
DEF_HELPER_2(glue(movmskps, SUFFIX), i32, env, Reg) DEF_HELPER_2(glue(movmskps, SUFFIX), i32, env, Reg)
DEF_HELPER_2(glue(movmskpd, SUFFIX), i32, env, Reg) DEF_HELPER_2(glue(movmskpd, SUFFIX), i32, env, Reg)
#endif #endif
DEF_HELPER_2(glue(pmovmskb, SUFFIX), i32, env, Reg) DEF_HELPER_4(glue(packsswb, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(packsswb, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(packuswb, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(packuswb, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(packssdw, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(packssdw, SUFFIX), void, env, Reg, Reg) #define UNPCK_OP(name, base) \
#define UNPCK_OP(base_name, base) \ DEF_HELPER_4(glue(punpck ## name ## bw, SUFFIX), void, env, Reg, Reg, Reg) \
DEF_HELPER_3(glue(punpck ## base_name ## bw, SUFFIX), void, env, Reg, Reg) \ DEF_HELPER_4(glue(punpck ## name ## wd, SUFFIX), void, env, Reg, Reg, Reg) \
DEF_HELPER_3(glue(punpck ## base_name ## wd, SUFFIX), void, env, Reg, Reg) \ DEF_HELPER_4(glue(punpck ## name ## dq, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(punpck ## base_name ## dq, SUFFIX), void, env, Reg, Reg)
UNPCK_OP(l, 0) UNPCK_OP(l, 0)
UNPCK_OP(h, 1) UNPCK_OP(h, 1)
#if SHIFT == 1 #if SHIFT >= 1
DEF_HELPER_3(glue(punpcklqdq, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(punpcklqdq, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(punpckhqdq, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(punpckhqdq, SUFFIX), void, env, Reg, Reg, Reg)
#endif #endif
/* 3DNow! float ops */ /* 3DNow! float ops */
@ -265,28 +275,25 @@ DEF_HELPER_3(pswapd, void, env, MMXReg, MMXReg)
#endif #endif
/* SSSE3 op helpers */ /* SSSE3 op helpers */
DEF_HELPER_3(glue(phaddw, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(phaddw, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(phaddd, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(phaddd, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(phaddsw, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(phaddsw, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(phsubw, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(phsubw, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(phsubd, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(phsubd, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(phsubsw, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(phsubsw, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(pabsb, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(pmaddubsw, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(pabsw, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(pmulhrsw, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(pabsd, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(pshufb, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(pmaddubsw, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(psignb, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(pmulhrsw, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(psignw, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(pshufb, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(psignd, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(psignb, SUFFIX), void, env, Reg, Reg) DEF_HELPER_5(glue(palignr, SUFFIX), void, env, Reg, Reg, Reg, i32)
DEF_HELPER_3(glue(psignw, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(psignd, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_4(glue(palignr, SUFFIX), void, env, Reg, Reg, s32)
/* SSE4.1 op helpers */ /* SSE4.1 op helpers */
#if SHIFT == 1 #if SHIFT >= 1
DEF_HELPER_3(glue(pblendvb, SUFFIX), void, env, Reg, Reg) DEF_HELPER_5(glue(pblendvb, SUFFIX), void, env, Reg, Reg, Reg, Reg)
DEF_HELPER_3(glue(blendvps, SUFFIX), void, env, Reg, Reg) DEF_HELPER_5(glue(blendvps, SUFFIX), void, env, Reg, Reg, Reg, Reg)
DEF_HELPER_3(glue(blendvpd, SUFFIX), void, env, Reg, Reg) DEF_HELPER_5(glue(blendvpd, SUFFIX), void, env, Reg, Reg, Reg, Reg)
DEF_HELPER_3(glue(ptest, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(glue(ptest, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(pmovsxbw, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(glue(pmovsxbw, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(pmovsxbd, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(glue(pmovsxbd, SUFFIX), void, env, Reg, Reg)
@ -300,34 +307,32 @@ DEF_HELPER_3(glue(pmovzxbq, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(pmovzxwd, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(glue(pmovzxwd, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(pmovzxwq, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(glue(pmovzxwq, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(pmovzxdq, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(glue(pmovzxdq, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(pmuldq, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(glue(pmovsldup, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(pcmpeqq, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(glue(pmovshdup, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(packusdw, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(glue(pmovdldup, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(pminsb, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(pmuldq, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(pminsd, SUFFIX), void, env, Reg, Reg) DEF_HELPER_4(glue(packusdw, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(pminuw, SUFFIX), void, env, Reg, Reg) #if SHIFT == 1
DEF_HELPER_3(glue(pminud, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(pmaxsb, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(pmaxsd, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(pmaxuw, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(pmaxud, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(pmulld, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(phminposuw, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(glue(phminposuw, SUFFIX), void, env, Reg, Reg)
#endif
DEF_HELPER_4(glue(roundps, SUFFIX), void, env, Reg, Reg, i32) DEF_HELPER_4(glue(roundps, SUFFIX), void, env, Reg, Reg, i32)
DEF_HELPER_4(glue(roundpd, SUFFIX), void, env, Reg, Reg, i32) DEF_HELPER_4(glue(roundpd, SUFFIX), void, env, Reg, Reg, i32)
DEF_HELPER_4(glue(roundss, SUFFIX), void, env, Reg, Reg, i32) #if SHIFT == 1
DEF_HELPER_4(glue(roundsd, SUFFIX), void, env, Reg, Reg, i32) DEF_HELPER_5(roundss_xmm, void, env, Reg, Reg, Reg, i32)
DEF_HELPER_4(glue(blendps, SUFFIX), void, env, Reg, Reg, i32) DEF_HELPER_5(roundsd_xmm, void, env, Reg, Reg, Reg, i32)
DEF_HELPER_4(glue(blendpd, SUFFIX), void, env, Reg, Reg, i32) #endif
DEF_HELPER_4(glue(pblendw, SUFFIX), void, env, Reg, Reg, i32) DEF_HELPER_5(glue(blendps, SUFFIX), void, env, Reg, Reg, Reg, i32)
DEF_HELPER_4(glue(dpps, SUFFIX), void, env, Reg, Reg, i32) DEF_HELPER_5(glue(blendpd, SUFFIX), void, env, Reg, Reg, Reg, i32)
DEF_HELPER_4(glue(dppd, SUFFIX), void, env, Reg, Reg, i32) DEF_HELPER_5(glue(pblendw, SUFFIX), void, env, Reg, Reg, Reg, i32)
DEF_HELPER_4(glue(mpsadbw, SUFFIX), void, env, Reg, Reg, i32) DEF_HELPER_5(glue(dpps, SUFFIX), void, env, Reg, Reg, Reg, i32)
#if SHIFT == 1
DEF_HELPER_5(glue(dppd, SUFFIX), void, env, Reg, Reg, Reg, i32)
#endif
DEF_HELPER_5(glue(mpsadbw, SUFFIX), void, env, Reg, Reg, Reg, i32)
#endif #endif
/* SSE4.2 op helpers */ /* SSE4.2 op helpers */
#if SHIFT == 1 #if SHIFT == 1
DEF_HELPER_3(glue(pcmpgtq, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_4(glue(pcmpestri, SUFFIX), void, env, Reg, Reg, i32) DEF_HELPER_4(glue(pcmpestri, SUFFIX), void, env, Reg, Reg, i32)
DEF_HELPER_4(glue(pcmpestrm, SUFFIX), void, env, Reg, Reg, i32) DEF_HELPER_4(glue(pcmpestrm, SUFFIX), void, env, Reg, Reg, i32)
DEF_HELPER_4(glue(pcmpistri, SUFFIX), void, env, Reg, Reg, i32) DEF_HELPER_4(glue(pcmpistri, SUFFIX), void, env, Reg, Reg, i32)
@ -336,14 +341,45 @@ DEF_HELPER_3(crc32, tl, i32, tl, i32)
#endif #endif
/* AES-NI op helpers */ /* AES-NI op helpers */
#if SHIFT >= 1
DEF_HELPER_4(glue(aesdec, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_4(glue(aesdeclast, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_4(glue(aesenc, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_4(glue(aesenclast, SUFFIX), void, env, Reg, Reg, Reg)
#if SHIFT == 1 #if SHIFT == 1
DEF_HELPER_3(glue(aesdec, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(aesdeclast, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(aesenc, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(aesenclast, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(aesimc, SUFFIX), void, env, Reg, Reg) DEF_HELPER_3(glue(aesimc, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_4(glue(aeskeygenassist, SUFFIX), void, env, Reg, Reg, i32) DEF_HELPER_4(glue(aeskeygenassist, SUFFIX), void, env, Reg, Reg, i32)
DEF_HELPER_4(glue(pclmulqdq, SUFFIX), void, env, Reg, Reg, i32) #endif
DEF_HELPER_5(glue(pclmulqdq, SUFFIX), void, env, Reg, Reg, Reg, i32)
#endif
/* AVX helpers */
#if SHIFT >= 1
DEF_HELPER_4(glue(vpermilpd, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_4(glue(vpermilps, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(vpermilpd_imm, SUFFIX), void, Reg, Reg, i32)
DEF_HELPER_3(glue(vpermilps_imm, SUFFIX), void, Reg, Reg, i32)
DEF_HELPER_4(glue(vpsrlvd, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_4(glue(vpsravd, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_4(glue(vpsllvd, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_4(glue(vpsrlvq, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_4(glue(vpsravq, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_4(glue(vpsllvq, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_3(glue(vtestps, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(vtestpd, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_4(glue(vpmaskmovd_st, SUFFIX), void, env, Reg, Reg, tl)
DEF_HELPER_4(glue(vpmaskmovq_st, SUFFIX), void, env, Reg, Reg, tl)
DEF_HELPER_4(glue(vpmaskmovd, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_4(glue(vpmaskmovq, SUFFIX), void, env, Reg, Reg, Reg)
DEF_HELPER_6(glue(vpgatherdd, SUFFIX), void, env, Reg, Reg, Reg, tl, i32)
DEF_HELPER_6(glue(vpgatherdq, SUFFIX), void, env, Reg, Reg, Reg, tl, i32)
DEF_HELPER_6(glue(vpgatherqd, SUFFIX), void, env, Reg, Reg, Reg, tl, i32)
DEF_HELPER_6(glue(vpgatherqq, SUFFIX), void, env, Reg, Reg, Reg, tl, i32)
#if SHIFT == 2
DEF_HELPER_3(vpermd_ymm, void, Reg, Reg, Reg)
DEF_HELPER_4(vpermdq_ymm, void, Reg, Reg, Reg, i32)
DEF_HELPER_3(vpermq_ymm, void, Reg, Reg, i32)
#endif
#endif #endif
#undef SHIFT #undef SHIFT
@ -354,6 +390,9 @@ DEF_HELPER_4(glue(pclmulqdq, SUFFIX), void, env, Reg, Reg, i32)
#undef SSE_HELPER_W #undef SSE_HELPER_W
#undef SSE_HELPER_L #undef SSE_HELPER_L
#undef SSE_HELPER_Q #undef SSE_HELPER_Q
#undef SSE_HELPER_S #undef SSE_HELPER_S3
#undef SSE_HELPER_S4
#undef SSE_HELPER_P3
#undef SSE_HELPER_P4
#undef SSE_HELPER_CMP #undef SSE_HELPER_CMP
#undef UNPCK_OP #undef UNPCK_OP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,249 @@
/*
* Decode table flags, mostly based on Intel SDM.
*
* Copyright (c) 2022 Red Hat, Inc.
*
* Author: Paolo Bonzini <pbonzini@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
typedef enum X86OpType {
X86_TYPE_None,
X86_TYPE_A, /* Implicit */
X86_TYPE_B, /* VEX.vvvv selects a GPR */
X86_TYPE_C, /* REG in the modrm byte selects a control register */
X86_TYPE_D, /* REG in the modrm byte selects a debug register */
X86_TYPE_E, /* ALU modrm operand */
X86_TYPE_F, /* EFLAGS/RFLAGS */
X86_TYPE_G, /* REG in the modrm byte selects a GPR */
X86_TYPE_H, /* For AVX, VEX.vvvv selects an XMM/YMM register */
X86_TYPE_I, /* Immediate */
X86_TYPE_J, /* Relative offset for a jump */
X86_TYPE_L, /* The upper 4 bits of the immediate select a 128-bit register */
X86_TYPE_M, /* modrm byte selects a memory operand */
X86_TYPE_N, /* R/M in the modrm byte selects an MMX register */
X86_TYPE_O, /* Absolute address encoded in the instruction */
X86_TYPE_P, /* reg in the modrm byte selects an MMX register */
X86_TYPE_Q, /* MMX modrm operand */
X86_TYPE_R, /* R/M in the modrm byte selects a register */
X86_TYPE_S, /* reg selects a segment register */
X86_TYPE_U, /* R/M in the modrm byte selects an XMM/YMM register */
X86_TYPE_V, /* reg in the modrm byte selects an XMM/YMM register */
X86_TYPE_W, /* XMM/YMM modrm operand */
X86_TYPE_X, /* string source */
X86_TYPE_Y, /* string destination */
/* Custom */
X86_TYPE_WM, /* modrm byte selects an XMM/YMM memory operand */
X86_TYPE_2op, /* 2-operand RMW instruction */
X86_TYPE_LoBits, /* encoded in bits 0-2 of the operand + REX.B */
X86_TYPE_0, /* Hard-coded GPRs (RAX..RDI) */
X86_TYPE_1,
X86_TYPE_2,
X86_TYPE_3,
X86_TYPE_4,
X86_TYPE_5,
X86_TYPE_6,
X86_TYPE_7,
X86_TYPE_ES, /* Hard-coded segment registers */
X86_TYPE_CS,
X86_TYPE_SS,
X86_TYPE_DS,
X86_TYPE_FS,
X86_TYPE_GS,
} X86OpType;
typedef enum X86OpSize {
X86_SIZE_None,
X86_SIZE_a, /* BOUND operand */
X86_SIZE_b, /* byte */
X86_SIZE_d, /* 32-bit */
X86_SIZE_dq, /* SSE/AVX 128-bit */
X86_SIZE_p, /* Far pointer */
X86_SIZE_pd, /* SSE/AVX packed double precision */
X86_SIZE_pi, /* MMX */
X86_SIZE_ps, /* SSE/AVX packed single precision */
X86_SIZE_q, /* 64-bit */
X86_SIZE_qq, /* AVX 256-bit */
X86_SIZE_s, /* Descriptor */
X86_SIZE_sd, /* SSE/AVX scalar double precision */
X86_SIZE_ss, /* SSE/AVX scalar single precision */
X86_SIZE_si, /* 32-bit GPR */
X86_SIZE_v, /* 16/32/64-bit, based on operand size */
X86_SIZE_w, /* 16-bit */
X86_SIZE_x, /* 128/256-bit, based on operand size */
X86_SIZE_y, /* 32/64-bit, based on operand size */
X86_SIZE_z, /* 16-bit for 16-bit operand size, else 32-bit */
/* Custom */
X86_SIZE_d64,
X86_SIZE_f64,
} X86OpSize;
typedef enum X86CPUIDFeature {
X86_FEAT_None,
X86_FEAT_3DNOW,
X86_FEAT_ADX,
X86_FEAT_AES,
X86_FEAT_AVX,
X86_FEAT_AVX2,
X86_FEAT_BMI1,
X86_FEAT_BMI2,
X86_FEAT_MOVBE,
X86_FEAT_PCLMULQDQ,
X86_FEAT_SSE,
X86_FEAT_SSE2,
X86_FEAT_SSE3,
X86_FEAT_SSSE3,
X86_FEAT_SSE41,
X86_FEAT_SSE42,
X86_FEAT_SSE4A,
} X86CPUIDFeature;
/* Execution flags */
typedef enum X86OpUnit {
X86_OP_SKIP, /* not valid or managed by emission function */
X86_OP_SEG, /* segment selector */
X86_OP_CR, /* control register */
X86_OP_DR, /* debug register */
X86_OP_INT, /* loaded into/stored from s->T0/T1 */
X86_OP_IMM, /* immediate */
X86_OP_SSE, /* address in either s->ptrX or s->A0 depending on has_ea */
X86_OP_MMX, /* address in either s->ptrX or s->A0 depending on has_ea */
} X86OpUnit;
typedef enum X86InsnSpecial {
X86_SPECIAL_None,
/* Always locked if it has a memory operand (XCHG) */
X86_SPECIAL_Locked,
/* Fault outside protected mode */
X86_SPECIAL_ProtMode,
/*
* Register operand 0/2 is zero extended to 32 bits. Rd/Mb or Rd/Mw
* in the manual.
*/
X86_SPECIAL_ZExtOp0,
X86_SPECIAL_ZExtOp2,
/*
* Register operand 2 is extended to full width, while a memory operand
* is doubled in size if VEX.L=1.
*/
X86_SPECIAL_AVXExtMov,
/*
* MMX instruction exists with no prefix; if there is no prefix, V/H/W/U operands
* become P/P/Q/N, and size "x" becomes "q".
*/
X86_SPECIAL_MMX,
/* Illegal or exclusive to 64-bit mode */
X86_SPECIAL_i64,
X86_SPECIAL_o64,
} X86InsnSpecial;
/*
* Special cases for instructions that operate on XMM/YMM registers. Intel
* retconned all of them to have VEX exception classes other than 0 and 13, so
* all these only matter for instructions that have a VEX exception class.
* Based on tables in the "AVX and SSE Instruction Exception Specification"
* section of the manual.
*/
typedef enum X86VEXSpecial {
/* Legacy SSE instructions that allow unaligned operands */
X86_VEX_SSEUnaligned,
/*
* Used for instructions that distinguish the XMM operand type with an
* instruction prefix; legacy SSE encodings will allow unaligned operands
* for scalar operands only (identified by a REP prefix). In this case,
* the decoding table uses "x" for the vector operands instead of specifying
* pd/ps/sd/ss individually.
*/
X86_VEX_REPScalar,
/*
* VEX instructions that only support 256-bit operands with AVX2 (Table 2-17
* column 3). Columns 2 and 4 (instructions limited to 256- and 127-bit
* operands respectively) are implicit in the presence of dq and qq
* operands, and thus handled by decode_op_size.
*/
X86_VEX_AVX2_256,
} X86VEXSpecial;
typedef struct X86OpEntry X86OpEntry;
typedef struct X86DecodedInsn X86DecodedInsn;
/* Decode function for multibyte opcodes. */
typedef void (*X86DecodeFunc)(DisasContext *s, CPUX86State *env, X86OpEntry *entry, uint8_t *b);
/* Code generation function. */
typedef void (*X86GenFunc)(DisasContext *s, CPUX86State *env, X86DecodedInsn *decode);
struct X86OpEntry {
/* Based on the is_decode flags. */
union {
X86GenFunc gen;
X86DecodeFunc decode;
};
/* op0 is always written, op1 and op2 are always read. */
X86OpType op0:8;
X86OpSize s0:8;
X86OpType op1:8;
X86OpSize s1:8;
X86OpType op2:8;
X86OpSize s2:8;
/* Must be I and b respectively if present. */
X86OpType op3:8;
X86OpSize s3:8;
X86InsnSpecial special:8;
X86CPUIDFeature cpuid:8;
unsigned vex_class:8;
X86VEXSpecial vex_special:8;
uint16_t valid_prefix:16;
bool is_decode:1;
};
typedef struct X86DecodedOp {
int8_t n;
MemOp ot; /* For b/c/d/p/s/q/v/w/y/z */
X86OpUnit unit;
bool has_ea;
int offset; /* For MMX and SSE */
/*
* This field is used internally by macros OP0_PTR/OP1_PTR/OP2_PTR,
* do not access directly!
*/
TCGv_ptr v_ptr;
} X86DecodedOp;
struct X86DecodedInsn {
X86OpEntry e;
X86DecodedOp op[3];
target_ulong immediate;
AddressParts mem;
uint8_t b;
};

2234
target/i386/tcg/emit.c.inc Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2559,6 +2559,22 @@ static void do_xsave_sse(CPUX86State *env, target_ulong ptr, uintptr_t ra)
} }
} }
static void do_xsave_ymmh(CPUX86State *env, target_ulong ptr, uintptr_t ra)
{
int i, nb_xmm_regs;
if (env->hflags & HF_CS64_MASK) {
nb_xmm_regs = 16;
} else {
nb_xmm_regs = 8;
}
for (i = 0; i < nb_xmm_regs; i++, ptr += 16) {
cpu_stq_data_ra(env, ptr, env->xmm_regs[i].ZMM_Q(2), ra);
cpu_stq_data_ra(env, ptr + 8, env->xmm_regs[i].ZMM_Q(3), ra);
}
}
static void do_xsave_bndregs(CPUX86State *env, target_ulong ptr, uintptr_t ra) static void do_xsave_bndregs(CPUX86State *env, target_ulong ptr, uintptr_t ra)
{ {
target_ulong addr = ptr + offsetof(XSaveBNDREG, bnd_regs); target_ulong addr = ptr + offsetof(XSaveBNDREG, bnd_regs);
@ -2651,6 +2667,9 @@ static void do_xsave(CPUX86State *env, target_ulong ptr, uint64_t rfbm,
if (opt & XSTATE_SSE_MASK) { if (opt & XSTATE_SSE_MASK) {
do_xsave_sse(env, ptr, ra); do_xsave_sse(env, ptr, ra);
} }
if (opt & XSTATE_YMM_MASK) {
do_xsave_ymmh(env, ptr + XO(avx_state), ra);
}
if (opt & XSTATE_BNDREGS_MASK) { if (opt & XSTATE_BNDREGS_MASK) {
do_xsave_bndregs(env, ptr + XO(bndreg_state), ra); do_xsave_bndregs(env, ptr + XO(bndreg_state), ra);
} }
@ -2725,6 +2744,54 @@ static void do_xrstor_sse(CPUX86State *env, target_ulong ptr, uintptr_t ra)
} }
} }
static void do_clear_sse(CPUX86State *env)
{
int i, nb_xmm_regs;
if (env->hflags & HF_CS64_MASK) {
nb_xmm_regs = 16;
} else {
nb_xmm_regs = 8;
}
for (i = 0; i < nb_xmm_regs; i++) {
env->xmm_regs[i].ZMM_Q(0) = 0;
env->xmm_regs[i].ZMM_Q(1) = 0;
}
}
static void do_xrstor_ymmh(CPUX86State *env, target_ulong ptr, uintptr_t ra)
{
int i, nb_xmm_regs;
if (env->hflags & HF_CS64_MASK) {
nb_xmm_regs = 16;
} else {
nb_xmm_regs = 8;
}
for (i = 0; i < nb_xmm_regs; i++, ptr += 16) {
env->xmm_regs[i].ZMM_Q(2) = cpu_ldq_data_ra(env, ptr, ra);
env->xmm_regs[i].ZMM_Q(3) = cpu_ldq_data_ra(env, ptr + 8, ra);
}
}
static void do_clear_ymmh(CPUX86State *env)
{
int i, nb_xmm_regs;
if (env->hflags & HF_CS64_MASK) {
nb_xmm_regs = 16;
} else {
nb_xmm_regs = 8;
}
for (i = 0; i < nb_xmm_regs; i++) {
env->xmm_regs[i].ZMM_Q(2) = 0;
env->xmm_regs[i].ZMM_Q(3) = 0;
}
}
static void do_xrstor_bndregs(CPUX86State *env, target_ulong ptr, uintptr_t ra) static void do_xrstor_bndregs(CPUX86State *env, target_ulong ptr, uintptr_t ra)
{ {
target_ulong addr = ptr + offsetof(XSaveBNDREG, bnd_regs); target_ulong addr = ptr + offsetof(XSaveBNDREG, bnd_regs);
@ -2831,9 +2898,14 @@ static void do_xrstor(CPUX86State *env, target_ulong ptr, uint64_t rfbm, uintptr
if (xstate_bv & XSTATE_SSE_MASK) { if (xstate_bv & XSTATE_SSE_MASK) {
do_xrstor_sse(env, ptr, ra); do_xrstor_sse(env, ptr, ra);
} else { } else {
/* ??? When AVX is implemented, we may have to be more do_clear_sse(env);
selective in the clearing. */ }
memset(env->xmm_regs, 0, sizeof(env->xmm_regs)); }
if (rfbm & XSTATE_YMM_MASK) {
if (xstate_bv & XSTATE_YMM_MASK) {
do_xrstor_ymmh(env, ptr + XO(avx_state), ra);
} else {
do_clear_ymmh(env);
} }
} }
if (rfbm & XSTATE_BNDREGS_MASK) { if (rfbm & XSTATE_BNDREGS_MASK) {
@ -2955,6 +3027,7 @@ void helper_xsetbv(CPUX86State *env, uint32_t ecx, uint64_t mask)
env->xcr0 = mask; env->xcr0 = mask;
cpu_sync_bndcs_hflags(env); cpu_sync_bndcs_hflags(env);
cpu_sync_avx_hflag(env);
return; return;
do_gpf: do_gpf:
@ -3053,14 +3126,11 @@ void helper_emms(CPUX86State *env)
*(uint32_t *)(env->fptags + 4) = 0x01010101; *(uint32_t *)(env->fptags + 4) = 0x01010101;
} }
/* XXX: suppress */
void helper_movq(CPUX86State *env, void *d, void *s)
{
*(uint64_t *)d = *(uint64_t *)s;
}
#define SHIFT 0 #define SHIFT 0
#include "ops_sse.h" #include "ops_sse.h"
#define SHIFT 1 #define SHIFT 1
#include "ops_sse.h" #include "ops_sse.h"
#define SHIFT 2
#include "ops_sse.h"

View File

@ -22,150 +22,274 @@
#include "exec/exec-all.h" #include "exec/exec-all.h"
#include "tcg/helper-tcg.h" #include "tcg/helper-tcg.h"
#define PG_ERROR_OK (-1) typedef struct TranslateParams {
target_ulong addr;
target_ulong cr3;
int pg_mode;
int mmu_idx;
int ptw_idx;
MMUAccessType access_type;
} TranslateParams;
typedef hwaddr (*MMUTranslateFunc)(CPUState *cs, hwaddr gphys, MMUAccessType access_type, typedef struct TranslateResult {
int *prot); hwaddr paddr;
int prot;
int page_size;
} TranslateResult;
#define GET_HPHYS(cs, gpa, access_type, prot) \ typedef enum TranslateFaultStage2 {
(get_hphys_func ? get_hphys_func(cs, gpa, access_type, prot) : gpa) S2_NONE,
S2_GPA,
S2_GPT,
} TranslateFaultStage2;
static int mmu_translate(CPUState *cs, hwaddr addr, MMUTranslateFunc get_hphys_func, typedef struct TranslateFault {
uint64_t cr3, int is_write1, int mmu_idx, int pg_mode, int exception_index;
hwaddr *xlat, int *page_size, int *prot) int error_code;
target_ulong cr2;
TranslateFaultStage2 stage2;
} TranslateFault;
typedef struct PTETranslate {
CPUX86State *env;
TranslateFault *err;
int ptw_idx;
void *haddr;
hwaddr gaddr;
} PTETranslate;
static bool ptw_translate(PTETranslate *inout, hwaddr addr)
{ {
X86CPU *cpu = X86_CPU(cs); CPUTLBEntryFull *full;
CPUX86State *env = &cpu->env; int flags;
uint64_t ptep, pte;
int32_t a20_mask; inout->gaddr = addr;
target_ulong pde_addr, pte_addr; flags = probe_access_full(inout->env, addr, MMU_DATA_STORE,
int error_code = 0; inout->ptw_idx, true, &inout->haddr, &full, 0);
int is_dirty, is_write, is_user;
uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits); if (unlikely(flags & TLB_INVALID_MASK)) {
uint32_t page_offset; TranslateFault *err = inout->err;
assert(inout->ptw_idx == MMU_NESTED_IDX);
err->exception_index = 0; /* unused */
err->error_code = inout->env->error_code;
err->cr2 = addr;
err->stage2 = S2_GPT;
return false;
}
return true;
}
static inline uint32_t ptw_ldl(const PTETranslate *in)
{
if (likely(in->haddr)) {
return ldl_p(in->haddr);
}
return cpu_ldl_mmuidx_ra(in->env, in->gaddr, in->ptw_idx, 0);
}
static inline uint64_t ptw_ldq(const PTETranslate *in)
{
if (likely(in->haddr)) {
return ldq_p(in->haddr);
}
return cpu_ldq_mmuidx_ra(in->env, in->gaddr, in->ptw_idx, 0);
}
/*
* Note that we can use a 32-bit cmpxchg for all page table entries,
* even 64-bit ones, because PG_PRESENT_MASK, PG_ACCESSED_MASK and
* PG_DIRTY_MASK are all in the low 32 bits.
*/
static bool ptw_setl_slow(const PTETranslate *in, uint32_t old, uint32_t new)
{
uint32_t cmp;
/* Does x86 really perform a rmw cycle on mmio for ptw? */
start_exclusive();
cmp = cpu_ldl_mmuidx_ra(in->env, in->gaddr, in->ptw_idx, 0);
if (cmp == old) {
cpu_stl_mmuidx_ra(in->env, in->gaddr, new, in->ptw_idx, 0);
}
end_exclusive();
return cmp == old;
}
static inline bool ptw_setl(const PTETranslate *in, uint32_t old, uint32_t set)
{
if (set & ~old) {
uint32_t new = old | set;
if (likely(in->haddr)) {
old = cpu_to_le32(old);
new = cpu_to_le32(new);
return qatomic_cmpxchg((uint32_t *)in->haddr, old, new) == old;
}
return ptw_setl_slow(in, old, new);
}
return true;
}
static bool mmu_translate(CPUX86State *env, const TranslateParams *in,
TranslateResult *out, TranslateFault *err)
{
const int32_t a20_mask = x86_get_a20_mask(env);
const target_ulong addr = in->addr;
const int pg_mode = in->pg_mode;
const bool is_user = (in->mmu_idx == MMU_USER_IDX);
const MMUAccessType access_type = in->access_type;
uint64_t ptep, pte, rsvd_mask;
PTETranslate pte_trans = {
.env = env,
.err = err,
.ptw_idx = in->ptw_idx,
};
hwaddr pte_addr, paddr;
uint32_t pkr; uint32_t pkr;
int page_size;
is_user = (mmu_idx == MMU_USER_IDX); restart_all:
is_write = is_write1 & 1; rsvd_mask = ~MAKE_64BIT_MASK(0, env_archcpu(env)->phys_bits);
a20_mask = x86_get_a20_mask(env); rsvd_mask &= PG_ADDRESS_MASK;
if (!(pg_mode & PG_MODE_NXE)) { if (!(pg_mode & PG_MODE_NXE)) {
rsvd_mask |= PG_NX_MASK; rsvd_mask |= PG_NX_MASK;
} }
if (pg_mode & PG_MODE_PAE) { if (pg_mode & PG_MODE_PAE) {
uint64_t pde, pdpe;
target_ulong pdpe_addr;
#ifdef TARGET_X86_64 #ifdef TARGET_X86_64
if (pg_mode & PG_MODE_LMA) { if (pg_mode & PG_MODE_LMA) {
bool la57 = pg_mode & PG_MODE_LA57; if (pg_mode & PG_MODE_LA57) {
uint64_t pml5e_addr, pml5e; /*
uint64_t pml4e_addr, pml4e; * Page table level 5
*/
if (la57) { pte_addr = ((in->cr3 & ~0xfff) +
pml5e_addr = ((cr3 & ~0xfff) +
(((addr >> 48) & 0x1ff) << 3)) & a20_mask; (((addr >> 48) & 0x1ff) << 3)) & a20_mask;
pml5e_addr = GET_HPHYS(cs, pml5e_addr, MMU_DATA_STORE, NULL); if (!ptw_translate(&pte_trans, pte_addr)) {
pml5e = x86_ldq_phys(cs, pml5e_addr); return false;
if (!(pml5e & PG_PRESENT_MASK)) { }
restart_5:
pte = ptw_ldq(&pte_trans);
if (!(pte & PG_PRESENT_MASK)) {
goto do_fault; goto do_fault;
} }
if (pml5e & (rsvd_mask | PG_PSE_MASK)) { if (pte & (rsvd_mask | PG_PSE_MASK)) {
goto do_fault_rsvd; goto do_fault_rsvd;
} }
if (!(pml5e & PG_ACCESSED_MASK)) { if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) {
pml5e |= PG_ACCESSED_MASK; goto restart_5;
x86_stl_phys_notdirty(cs, pml5e_addr, pml5e);
} }
ptep = pml5e ^ PG_NX_MASK; ptep = pte ^ PG_NX_MASK;
} else { } else {
pml5e = cr3; pte = in->cr3;
ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
} }
pml4e_addr = ((pml5e & PG_ADDRESS_MASK) + /*
* Page table level 4
*/
pte_addr = ((pte & PG_ADDRESS_MASK) +
(((addr >> 39) & 0x1ff) << 3)) & a20_mask; (((addr >> 39) & 0x1ff) << 3)) & a20_mask;
pml4e_addr = GET_HPHYS(cs, pml4e_addr, MMU_DATA_STORE, NULL); if (!ptw_translate(&pte_trans, pte_addr)) {
pml4e = x86_ldq_phys(cs, pml4e_addr); return false;
if (!(pml4e & PG_PRESENT_MASK)) { }
restart_4:
pte = ptw_ldq(&pte_trans);
if (!(pte & PG_PRESENT_MASK)) {
goto do_fault; goto do_fault;
} }
if (pml4e & (rsvd_mask | PG_PSE_MASK)) { if (pte & (rsvd_mask | PG_PSE_MASK)) {
goto do_fault_rsvd; goto do_fault_rsvd;
} }
if (!(pml4e & PG_ACCESSED_MASK)) { if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) {
pml4e |= PG_ACCESSED_MASK; goto restart_4;
x86_stl_phys_notdirty(cs, pml4e_addr, pml4e);
} }
ptep &= pml4e ^ PG_NX_MASK; ptep &= pte ^ PG_NX_MASK;
pdpe_addr = ((pml4e & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3)) &
a20_mask; /*
pdpe_addr = GET_HPHYS(cs, pdpe_addr, MMU_DATA_STORE, NULL); * Page table level 3
pdpe = x86_ldq_phys(cs, pdpe_addr); */
if (!(pdpe & PG_PRESENT_MASK)) { pte_addr = ((pte & PG_ADDRESS_MASK) +
(((addr >> 30) & 0x1ff) << 3)) & a20_mask;
if (!ptw_translate(&pte_trans, pte_addr)) {
return false;
}
restart_3_lma:
pte = ptw_ldq(&pte_trans);
if (!(pte & PG_PRESENT_MASK)) {
goto do_fault; goto do_fault;
} }
if (pdpe & rsvd_mask) { if (pte & rsvd_mask) {
goto do_fault_rsvd; goto do_fault_rsvd;
} }
ptep &= pdpe ^ PG_NX_MASK; if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) {
if (!(pdpe & PG_ACCESSED_MASK)) { goto restart_3_lma;
pdpe |= PG_ACCESSED_MASK;
x86_stl_phys_notdirty(cs, pdpe_addr, pdpe);
} }
if (pdpe & PG_PSE_MASK) { ptep &= pte ^ PG_NX_MASK;
if (pte & PG_PSE_MASK) {
/* 1 GB page */ /* 1 GB page */
*page_size = 1024 * 1024 * 1024; page_size = 1024 * 1024 * 1024;
pte_addr = pdpe_addr;
pte = pdpe;
goto do_check_protect; goto do_check_protect;
} }
} else } else
#endif #endif
{ {
/* XXX: load them when cr3 is loaded ? */ /*
pdpe_addr = ((cr3 & ~0x1f) + ((addr >> 27) & 0x18)) & * Page table level 3
a20_mask; */
pdpe_addr = GET_HPHYS(cs, pdpe_addr, MMU_DATA_STORE, NULL); pte_addr = ((in->cr3 & ~0x1f) + ((addr >> 27) & 0x18)) & a20_mask;
pdpe = x86_ldq_phys(cs, pdpe_addr); if (!ptw_translate(&pte_trans, pte_addr)) {
if (!(pdpe & PG_PRESENT_MASK)) { return false;
goto do_fault;
} }
rsvd_mask |= PG_HI_USER_MASK; rsvd_mask |= PG_HI_USER_MASK;
if (pdpe & (rsvd_mask | PG_NX_MASK)) { restart_3_nolma:
pte = ptw_ldq(&pte_trans);
if (!(pte & PG_PRESENT_MASK)) {
goto do_fault;
}
if (pte & (rsvd_mask | PG_NX_MASK)) {
goto do_fault_rsvd; goto do_fault_rsvd;
} }
if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) {
goto restart_3_nolma;
}
ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
} }
pde_addr = ((pdpe & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3)) & /*
a20_mask; * Page table level 2
pde_addr = GET_HPHYS(cs, pde_addr, MMU_DATA_STORE, NULL); */
pde = x86_ldq_phys(cs, pde_addr); pte_addr = ((pte & PG_ADDRESS_MASK) +
if (!(pde & PG_PRESENT_MASK)) { (((addr >> 21) & 0x1ff) << 3)) & a20_mask;
if (!ptw_translate(&pte_trans, pte_addr)) {
return false;
}
restart_2_pae:
pte = ptw_ldq(&pte_trans);
if (!(pte & PG_PRESENT_MASK)) {
goto do_fault; goto do_fault;
} }
if (pde & rsvd_mask) { if (pte & rsvd_mask) {
goto do_fault_rsvd; goto do_fault_rsvd;
} }
ptep &= pde ^ PG_NX_MASK; if (pte & PG_PSE_MASK) {
if (pde & PG_PSE_MASK) {
/* 2 MB page */ /* 2 MB page */
*page_size = 2048 * 1024; page_size = 2048 * 1024;
pte_addr = pde_addr; ptep &= pte ^ PG_NX_MASK;
pte = pde;
goto do_check_protect; goto do_check_protect;
} }
/* 4 KB page */ if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) {
if (!(pde & PG_ACCESSED_MASK)) { goto restart_2_pae;
pde |= PG_ACCESSED_MASK;
x86_stl_phys_notdirty(cs, pde_addr, pde);
} }
pte_addr = ((pde & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3)) & ptep &= pte ^ PG_NX_MASK;
a20_mask;
pte_addr = GET_HPHYS(cs, pte_addr, MMU_DATA_STORE, NULL); /*
pte = x86_ldq_phys(cs, pte_addr); * Page table level 1
*/
pte_addr = ((pte & PG_ADDRESS_MASK) +
(((addr >> 12) & 0x1ff) << 3)) & a20_mask;
if (!ptw_translate(&pte_trans, pte_addr)) {
return false;
}
pte = ptw_ldq(&pte_trans);
if (!(pte & PG_PRESENT_MASK)) { if (!(pte & PG_PRESENT_MASK)) {
goto do_fault; goto do_fault;
} }
@ -174,54 +298,56 @@ static int mmu_translate(CPUState *cs, hwaddr addr, MMUTranslateFunc get_hphys_f
} }
/* combine pde and pte nx, user and rw protections */ /* combine pde and pte nx, user and rw protections */
ptep &= pte ^ PG_NX_MASK; ptep &= pte ^ PG_NX_MASK;
*page_size = 4096; page_size = 4096;
} else { } else {
uint32_t pde; /*
* Page table level 2
/* page directory entry */ */
pde_addr = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)) & pte_addr = ((in->cr3 & ~0xfff) + ((addr >> 20) & 0xffc)) & a20_mask;
a20_mask; if (!ptw_translate(&pte_trans, pte_addr)) {
pde_addr = GET_HPHYS(cs, pde_addr, MMU_DATA_STORE, NULL); return false;
pde = x86_ldl_phys(cs, pde_addr); }
if (!(pde & PG_PRESENT_MASK)) { restart_2_nopae:
pte = ptw_ldl(&pte_trans);
if (!(pte & PG_PRESENT_MASK)) {
goto do_fault; goto do_fault;
} }
ptep = pde | PG_NX_MASK; ptep = pte | PG_NX_MASK;
/* if PSE bit is set, then we use a 4MB page */ /* if PSE bit is set, then we use a 4MB page */
if ((pde & PG_PSE_MASK) && (pg_mode & PG_MODE_PSE)) { if ((pte & PG_PSE_MASK) && (pg_mode & PG_MODE_PSE)) {
*page_size = 4096 * 1024; page_size = 4096 * 1024;
pte_addr = pde_addr; /*
* Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved.
/* Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved.
* Leave bits 20-13 in place for setting accessed/dirty bits below. * Leave bits 20-13 in place for setting accessed/dirty bits below.
*/ */
pte = pde | ((pde & 0x1fe000LL) << (32 - 13)); pte = (uint32_t)pte | ((pte & 0x1fe000LL) << (32 - 13));
rsvd_mask = 0x200000; rsvd_mask = 0x200000;
goto do_check_protect_pse36; goto do_check_protect_pse36;
} }
if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) {
if (!(pde & PG_ACCESSED_MASK)) { goto restart_2_nopae;
pde |= PG_ACCESSED_MASK;
x86_stl_phys_notdirty(cs, pde_addr, pde);
} }
/* page directory entry */ /*
pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & * Page table level 1
a20_mask; */
pte_addr = GET_HPHYS(cs, pte_addr, MMU_DATA_STORE, NULL); pte_addr = ((pte & ~0xfffu) + ((addr >> 10) & 0xffc)) & a20_mask;
pte = x86_ldl_phys(cs, pte_addr); if (!ptw_translate(&pte_trans, pte_addr)) {
return false;
}
pte = ptw_ldl(&pte_trans);
if (!(pte & PG_PRESENT_MASK)) { if (!(pte & PG_PRESENT_MASK)) {
goto do_fault; goto do_fault;
} }
/* combine pde and pte user and rw protections */ /* combine pde and pte user and rw protections */
ptep &= pte | PG_NX_MASK; ptep &= pte | PG_NX_MASK;
*page_size = 4096; page_size = 4096;
rsvd_mask = 0; rsvd_mask = 0;
} }
do_check_protect: do_check_protect:
rsvd_mask |= (*page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK; rsvd_mask |= (page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK;
do_check_protect_pse36: do_check_protect_pse36:
if (pte & rsvd_mask) { if (pte & rsvd_mask) {
goto do_fault_rsvd; goto do_fault_rsvd;
@ -233,17 +359,17 @@ do_check_protect_pse36:
goto do_fault_protect; goto do_fault_protect;
} }
*prot = 0; int prot = 0;
if (mmu_idx != MMU_KSMAP_IDX || !(ptep & PG_USER_MASK)) { if (in->mmu_idx != MMU_KSMAP_IDX || !(ptep & PG_USER_MASK)) {
*prot |= PAGE_READ; prot |= PAGE_READ;
if ((ptep & PG_RW_MASK) || !(is_user || (pg_mode & PG_MODE_WP))) { if ((ptep & PG_RW_MASK) || !(is_user || (pg_mode & PG_MODE_WP))) {
*prot |= PAGE_WRITE; prot |= PAGE_WRITE;
} }
} }
if (!(ptep & PG_NX_MASK) && if (!(ptep & PG_NX_MASK) &&
(mmu_idx == MMU_USER_IDX || (is_user ||
!((pg_mode & PG_MODE_SMEP) && (ptep & PG_USER_MASK)))) { !((pg_mode & PG_MODE_SMEP) && (ptep & PG_USER_MASK)))) {
*prot |= PAGE_EXEC; prot |= PAGE_EXEC;
} }
if (ptep & PG_USER_MASK) { if (ptep & PG_USER_MASK) {
@ -262,182 +388,246 @@ do_check_protect_pse36:
} else if (pkr_wd && (is_user || (pg_mode & PG_MODE_WP))) { } else if (pkr_wd && (is_user || (pg_mode & PG_MODE_WP))) {
pkr_prot &= ~PAGE_WRITE; pkr_prot &= ~PAGE_WRITE;
} }
if ((pkr_prot & (1 << access_type)) == 0) {
*prot &= pkr_prot; goto do_fault_pk_protect;
if ((pkr_prot & (1 << is_write1)) == 0) {
assert(is_write1 != 2);
error_code |= PG_ERROR_PK_MASK;
goto do_fault_protect;
} }
prot &= pkr_prot;
} }
if ((*prot & (1 << is_write1)) == 0) { if ((prot & (1 << access_type)) == 0) {
goto do_fault_protect; goto do_fault_protect;
} }
/* yes, it can! */ /* yes, it can! */
is_dirty = is_write && !(pte & PG_DIRTY_MASK); {
if (!(pte & PG_ACCESSED_MASK) || is_dirty) { uint32_t set = PG_ACCESSED_MASK;
pte |= PG_ACCESSED_MASK; if (access_type == MMU_DATA_STORE) {
if (is_dirty) { set |= PG_DIRTY_MASK;
pte |= PG_DIRTY_MASK; } else if (!(pte & PG_DIRTY_MASK)) {
/*
* Only set write access if already dirty...
* otherwise wait for dirty access.
*/
prot &= ~PAGE_WRITE;
} }
x86_stl_phys_notdirty(cs, pte_addr, pte); if (!ptw_setl(&pte_trans, pte, set)) {
/*
* We can arrive here from any of 3 levels and 2 formats.
* The only safe thing is to restart the entire lookup.
*/
goto restart_all;
} }
if (!(pte & PG_DIRTY_MASK)) {
/* only set write access if already dirty... otherwise wait
for dirty access */
assert(!is_write);
*prot &= ~PAGE_WRITE;
} }
pte = pte & a20_mask;
/* align to page_size */ /* align to page_size */
pte &= PG_ADDRESS_MASK & ~(*page_size - 1); paddr = (pte & a20_mask & PG_ADDRESS_MASK & ~(page_size - 1))
page_offset = addr & (*page_size - 1); | (addr & (page_size - 1));
*xlat = GET_HPHYS(cs, pte + page_offset, is_write1, prot);
return PG_ERROR_OK;
do_fault_rsvd: if (in->ptw_idx == MMU_NESTED_IDX) {
error_code |= PG_ERROR_RSVD_MASK; CPUTLBEntryFull *full;
do_fault_protect: int flags, nested_page_size;
error_code |= PG_ERROR_P_MASK;
do_fault:
error_code |= (is_write << PG_ERROR_W_BIT);
if (is_user)
error_code |= PG_ERROR_U_MASK;
if (is_write1 == 2 &&
((pg_mode & PG_MODE_NXE) || (pg_mode & PG_MODE_SMEP)))
error_code |= PG_ERROR_I_D_MASK;
return error_code;
}
hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type, flags = probe_access_full(env, paddr, access_type,
int *prot) MMU_NESTED_IDX, true,
{ &pte_trans.haddr, &full, 0);
CPUX86State *env = &X86_CPU(cs)->env; if (unlikely(flags & TLB_INVALID_MASK)) {
uint64_t exit_info_1; err->exception_index = 0; /* unused */
int page_size; err->error_code = env->error_code;
int next_prot; err->cr2 = paddr;
hwaddr hphys; err->stage2 = S2_GPA;
return false;
if (likely(!(env->hflags2 & HF2_NPT_MASK))) {
return gphys;
} }
exit_info_1 = mmu_translate(cs, gphys, NULL, env->nested_cr3, /* Merge stage1 & stage2 protection bits. */
access_type, MMU_USER_IDX, env->nested_pg_mode, prot &= full->prot;
&hphys, &page_size, &next_prot);
if (exit_info_1 == PG_ERROR_OK) { /* Re-verify resulting protection. */
if (prot) { if ((prot & (1 << access_type)) == 0) {
*prot &= next_prot; goto do_fault_protect;
}
return hphys;
} }
x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), /* Merge stage1 & stage2 addresses to final physical address. */
gphys); nested_page_size = 1 << full->lg_page_size;
if (prot) { paddr = (full->phys_addr & ~(nested_page_size - 1))
exit_info_1 |= SVM_NPTEXIT_GPA; | (paddr & (nested_page_size - 1));
} else { /* page table access */
exit_info_1 |= SVM_NPTEXIT_GPT;
}
cpu_vmexit(env, SVM_EXIT_NPF, exit_info_1, env->retaddr);
}
/* return value: /*
* -1 = cannot handle fault * Use the larger of stage1 & stage2 page sizes, so that
* 0 = nothing more to do * invalidation works.
* 1 = generate PF fault
*/ */
static int handle_mmu_fault(CPUState *cs, vaddr addr, int size, if (nested_page_size > page_size) {
int is_write1, int mmu_idx) page_size = nested_page_size;
}
}
out->paddr = paddr;
out->prot = prot;
out->page_size = page_size;
return true;
int error_code;
do_fault_rsvd:
error_code = PG_ERROR_RSVD_MASK;
goto do_fault_cont;
do_fault_protect:
error_code = PG_ERROR_P_MASK;
goto do_fault_cont;
do_fault_pk_protect:
assert(access_type != MMU_INST_FETCH);
error_code = PG_ERROR_PK_MASK | PG_ERROR_P_MASK;
goto do_fault_cont;
do_fault:
error_code = 0;
do_fault_cont:
if (is_user) {
error_code |= PG_ERROR_U_MASK;
}
switch (access_type) {
case MMU_DATA_LOAD:
break;
case MMU_DATA_STORE:
error_code |= PG_ERROR_W_MASK;
break;
case MMU_INST_FETCH:
if (pg_mode & (PG_MODE_NXE | PG_MODE_SMEP)) {
error_code |= PG_ERROR_I_D_MASK;
}
break;
}
err->exception_index = EXCP0E_PAGE;
err->error_code = error_code;
err->cr2 = addr;
err->stage2 = S2_NONE;
return false;
}
static G_NORETURN void raise_stage2(CPUX86State *env, TranslateFault *err,
uintptr_t retaddr)
{ {
X86CPU *cpu = X86_CPU(cs); uint64_t exit_info_1 = err->error_code;
CPUX86State *env = &cpu->env;
int error_code = PG_ERROR_OK;
int pg_mode, prot, page_size;
int32_t a20_mask;
hwaddr paddr;
hwaddr vaddr;
#if defined(DEBUG_MMU) switch (err->stage2) {
printf("MMU fault: addr=%" VADDR_PRIx " w=%d mmu=%d eip=" TARGET_FMT_lx "\n", case S2_GPT:
addr, is_write1, mmu_idx, env->eip); exit_info_1 |= SVM_NPTEXIT_GPT;
#endif break;
case S2_GPA:
exit_info_1 |= SVM_NPTEXIT_GPA;
break;
default:
g_assert_not_reached();
}
if (!(env->cr[0] & CR0_PG_MASK)) { x86_stq_phys(env_cpu(env),
a20_mask = x86_get_a20_mask(env); env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
paddr = addr & a20_mask; err->cr2);
cpu_vmexit(env, SVM_EXIT_NPF, exit_info_1, retaddr);
}
static bool get_physical_address(CPUX86State *env, vaddr addr,
MMUAccessType access_type, int mmu_idx,
TranslateResult *out, TranslateFault *err)
{
TranslateParams in;
bool use_stage2 = env->hflags2 & HF2_NPT_MASK;
in.addr = addr;
in.access_type = access_type;
switch (mmu_idx) {
case MMU_PHYS_IDX:
break;
case MMU_NESTED_IDX:
if (likely(use_stage2)) {
in.cr3 = env->nested_cr3;
in.pg_mode = env->nested_pg_mode;
in.mmu_idx = MMU_USER_IDX;
in.ptw_idx = MMU_PHYS_IDX;
if (!mmu_translate(env, &in, out, err)) {
err->stage2 = S2_GPA;
return false;
}
return true;
}
break;
default:
in.cr3 = env->cr[3];
in.mmu_idx = mmu_idx;
in.ptw_idx = use_stage2 ? MMU_NESTED_IDX : MMU_PHYS_IDX;
in.pg_mode = get_pg_mode(env);
if (likely(in.pg_mode)) {
if (in.pg_mode & PG_MODE_LMA) {
/* test virtual address sign extension */
int shift = in.pg_mode & PG_MODE_LA57 ? 56 : 47;
int64_t sext = (int64_t)addr >> shift;
if (sext != 0 && sext != -1) {
err->exception_index = EXCP0D_GPF;
err->error_code = 0;
err->cr2 = addr;
return false;
}
}
return mmu_translate(env, &in, out, err);
}
break;
}
/* Translation disabled. */
out->paddr = addr & x86_get_a20_mask(env);
#ifdef TARGET_X86_64 #ifdef TARGET_X86_64
if (!(env->hflags & HF_LMA_MASK)) { if (!(env->hflags & HF_LMA_MASK)) {
/* Without long mode we can only address 32bits in real mode */ /* Without long mode we can only address 32bits in real mode */
paddr = (uint32_t)paddr; out->paddr = (uint32_t)out->paddr;
} }
#endif #endif
prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; out->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
page_size = 4096; out->page_size = TARGET_PAGE_SIZE;
} else { return true;
pg_mode = get_pg_mode(env);
if (pg_mode & PG_MODE_LMA) {
int32_t sext;
/* test virtual address sign extension */
sext = (int64_t)addr >> (pg_mode & PG_MODE_LA57 ? 56 : 47);
if (sext != 0 && sext != -1) {
env->error_code = 0;
cs->exception_index = EXCP0D_GPF;
return 1;
}
}
error_code = mmu_translate(cs, addr, get_hphys, env->cr[3], is_write1,
mmu_idx, pg_mode,
&paddr, &page_size, &prot);
}
if (error_code == PG_ERROR_OK) {
/* Even if 4MB pages, we map only one 4KB page in the cache to
avoid filling it too fast */
vaddr = addr & TARGET_PAGE_MASK;
paddr &= TARGET_PAGE_MASK;
assert(prot & (1 << is_write1));
tlb_set_page_with_attrs(cs, vaddr, paddr, cpu_get_mem_attrs(env),
prot, mmu_idx, page_size);
return 0;
} else {
if (env->intercept_exceptions & (1 << EXCP0E_PAGE)) {
/* cr2 is not modified in case of exceptions */
x86_stq_phys(cs,
env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
addr);
} else {
env->cr[2] = addr;
}
env->error_code = error_code;
cs->exception_index = EXCP0E_PAGE;
return 1;
}
} }
bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size, bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
MMUAccessType access_type, int mmu_idx, MMUAccessType access_type, int mmu_idx,
bool probe, uintptr_t retaddr) bool probe, uintptr_t retaddr)
{ {
X86CPU *cpu = X86_CPU(cs); CPUX86State *env = cs->env_ptr;
CPUX86State *env = &cpu->env; TranslateResult out;
TranslateFault err;
env->retaddr = retaddr; if (get_physical_address(env, addr, access_type, mmu_idx, &out, &err)) {
if (handle_mmu_fault(cs, addr, size, access_type, mmu_idx)) { /*
/* FIXME: On error in get_hphys we have already jumped out. */ * Even if 4MB pages, we map only one 4KB page in the cache to
g_assert(!probe); * avoid filling it too fast.
raise_exception_err_ra(env, cs->exception_index, */
env->error_code, retaddr); assert(out.prot & (1 << access_type));
} tlb_set_page_with_attrs(cs, addr & TARGET_PAGE_MASK,
out.paddr & TARGET_PAGE_MASK,
cpu_get_mem_attrs(env),
out.prot, mmu_idx, out.page_size);
return true; return true;
}
if (probe) {
/* This will be used if recursing for stage2 translation. */
env->error_code = err.error_code;
return false;
}
if (err.stage2 != S2_NONE) {
raise_stage2(env, &err, retaddr);
}
if (env->intercept_exceptions & (1 << err.exception_index)) {
/* cr2 is not modified in case of exceptions */
x86_stq_phys(cs, env->vm_vmcb +
offsetof(struct vmcb, control.exit_info_2),
err.cr2);
} else {
env->cr[2] = err.cr2;
}
raise_exception_err_ra(env, err.exception_index, err.error_code, retaddr);
} }
G_NORETURN void x86_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, G_NORETURN void x86_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr,

View File

@ -27,19 +27,19 @@
/* Secure Virtual Machine helpers */ /* Secure Virtual Machine helpers */
static inline void svm_save_seg(CPUX86State *env, hwaddr addr, static void svm_save_seg(CPUX86State *env, int mmu_idx, hwaddr addr,
const SegmentCache *sc) const SegmentCache *sc)
{ {
CPUState *cs = env_cpu(env); cpu_stw_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, selector),
sc->selector, mmu_idx, 0);
x86_stw_phys(cs, addr + offsetof(struct vmcb_seg, selector), cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, base),
sc->selector); sc->base, mmu_idx, 0);
x86_stq_phys(cs, addr + offsetof(struct vmcb_seg, base), cpu_stl_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, limit),
sc->base); sc->limit, mmu_idx, 0);
x86_stl_phys(cs, addr + offsetof(struct vmcb_seg, limit), cpu_stw_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, attrib),
sc->limit); ((sc->flags >> 8) & 0xff)
x86_stw_phys(cs, addr + offsetof(struct vmcb_seg, attrib), | ((sc->flags >> 12) & 0x0f00),
((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00)); mmu_idx, 0);
} }
/* /*
@ -52,29 +52,36 @@ static inline void svm_canonicalization(CPUX86State *env, target_ulong *seg_base
*seg_base = ((((long) *seg_base) << shift_amt) >> shift_amt); *seg_base = ((((long) *seg_base) << shift_amt) >> shift_amt);
} }
static inline void svm_load_seg(CPUX86State *env, hwaddr addr, static void svm_load_seg(CPUX86State *env, int mmu_idx, hwaddr addr,
SegmentCache *sc) SegmentCache *sc)
{ {
CPUState *cs = env_cpu(env);
unsigned int flags; unsigned int flags;
sc->selector = x86_lduw_phys(cs, sc->selector =
addr + offsetof(struct vmcb_seg, selector)); cpu_lduw_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, selector),
sc->base = x86_ldq_phys(cs, addr + offsetof(struct vmcb_seg, base)); mmu_idx, 0);
sc->limit = x86_ldl_phys(cs, addr + offsetof(struct vmcb_seg, limit)); sc->base =
flags = x86_lduw_phys(cs, addr + offsetof(struct vmcb_seg, attrib)); cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, base),
mmu_idx, 0);
sc->limit =
cpu_ldl_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, limit),
mmu_idx, 0);
flags =
cpu_lduw_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, attrib),
mmu_idx, 0);
sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12); sc->flags = ((flags & 0xff) << 8) | ((flags & 0x0f00) << 12);
svm_canonicalization(env, &sc->base); svm_canonicalization(env, &sc->base);
} }
static inline void svm_load_seg_cache(CPUX86State *env, hwaddr addr, static void svm_load_seg_cache(CPUX86State *env, int mmu_idx,
int seg_reg) hwaddr addr, int seg_reg)
{ {
SegmentCache sc1, *sc = &sc1; SegmentCache sc;
svm_load_seg(env, addr, sc); svm_load_seg(env, mmu_idx, addr, &sc);
cpu_x86_load_seg_cache(env, seg_reg, sc->selector, cpu_x86_load_seg_cache(env, seg_reg, sc.selector,
sc->base, sc->limit, sc->flags); sc.base, sc.limit, sc.flags);
} }
static inline bool is_efer_invalid_state (CPUX86State *env) static inline bool is_efer_invalid_state (CPUX86State *env)
@ -199,13 +206,17 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
env->vm_hsave + offsetof(struct vmcb, save.rflags), env->vm_hsave + offsetof(struct vmcb, save.rflags),
cpu_compute_eflags(env)); cpu_compute_eflags(env));
svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.es), svm_save_seg(env, MMU_PHYS_IDX,
env->vm_hsave + offsetof(struct vmcb, save.es),
&env->segs[R_ES]); &env->segs[R_ES]);
svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.cs), svm_save_seg(env, MMU_PHYS_IDX,
env->vm_hsave + offsetof(struct vmcb, save.cs),
&env->segs[R_CS]); &env->segs[R_CS]);
svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.ss), svm_save_seg(env, MMU_PHYS_IDX,
env->vm_hsave + offsetof(struct vmcb, save.ss),
&env->segs[R_SS]); &env->segs[R_SS]);
svm_save_seg(env, env->vm_hsave + offsetof(struct vmcb, save.ds), svm_save_seg(env, MMU_PHYS_IDX,
env->vm_hsave + offsetof(struct vmcb, save.ds),
&env->segs[R_DS]); &env->segs[R_DS]);
x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.rip), x86_stq_phys(cs, env->vm_hsave + offsetof(struct vmcb, save.rip),
@ -271,6 +282,8 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
env->hflags2 |= HF2_NPT_MASK; env->hflags2 |= HF2_NPT_MASK;
env->nested_pg_mode = get_pg_mode(env) & PG_MODE_SVM_MASK; env->nested_pg_mode = get_pg_mode(env) & PG_MODE_SVM_MASK;
tlb_flush_by_mmuidx(cs, 1 << MMU_NESTED_IDX);
} }
/* enable intercepts */ /* enable intercepts */
@ -323,18 +336,18 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
save.rflags)), save.rflags)),
~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK)); ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.es), svm_load_seg_cache(env, MMU_PHYS_IDX,
R_ES); env->vm_vmcb + offsetof(struct vmcb, save.es), R_ES);
svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.cs), svm_load_seg_cache(env, MMU_PHYS_IDX,
R_CS); env->vm_vmcb + offsetof(struct vmcb, save.cs), R_CS);
svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ss), svm_load_seg_cache(env, MMU_PHYS_IDX,
R_SS); env->vm_vmcb + offsetof(struct vmcb, save.ss), R_SS);
svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ds), svm_load_seg_cache(env, MMU_PHYS_IDX,
R_DS); env->vm_vmcb + offsetof(struct vmcb, save.ds), R_DS);
svm_load_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.idtr), svm_load_seg(env, MMU_PHYS_IDX,
&env->idt); env->vm_vmcb + offsetof(struct vmcb, save.idtr), &env->idt);
svm_load_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.gdtr), svm_load_seg(env, MMU_PHYS_IDX,
&env->gdt); env->vm_vmcb + offsetof(struct vmcb, save.gdtr), &env->gdt);
env->eip = x86_ldq_phys(cs, env->eip = x86_ldq_phys(cs,
env->vm_vmcb + offsetof(struct vmcb, save.rip)); env->vm_vmcb + offsetof(struct vmcb, save.rip));
@ -449,9 +462,8 @@ void helper_vmmcall(CPUX86State *env)
void helper_vmload(CPUX86State *env, int aflag) void helper_vmload(CPUX86State *env, int aflag)
{ {
CPUState *cs = env_cpu(env); int mmu_idx = MMU_PHYS_IDX;
target_ulong addr; target_ulong addr;
int prot;
cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0, GETPC()); cpu_svm_check_intercept_param(env, SVM_EXIT_VMLOAD, 0, GETPC());
@ -462,43 +474,52 @@ void helper_vmload(CPUX86State *env, int aflag)
} }
if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMLOAD, GETPC())) { if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMLOAD, GETPC())) {
addr = get_hphys(cs, addr, MMU_DATA_LOAD, &prot); mmu_idx = MMU_NESTED_IDX;
} }
qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmload! " TARGET_FMT_lx svm_load_seg_cache(env, mmu_idx,
"\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n", addr + offsetof(struct vmcb, save.fs), R_FS);
addr, x86_ldq_phys(cs, addr + offsetof(struct vmcb, svm_load_seg_cache(env, mmu_idx,
save.fs.base)), addr + offsetof(struct vmcb, save.gs), R_GS);
env->segs[R_FS].base); svm_load_seg(env, mmu_idx,
addr + offsetof(struct vmcb, save.tr), &env->tr);
svm_load_seg_cache(env, addr + offsetof(struct vmcb, save.fs), R_FS); svm_load_seg(env, mmu_idx,
svm_load_seg_cache(env, addr + offsetof(struct vmcb, save.gs), R_GS); addr + offsetof(struct vmcb, save.ldtr), &env->ldt);
svm_load_seg(env, addr + offsetof(struct vmcb, save.tr), &env->tr);
svm_load_seg(env, addr + offsetof(struct vmcb, save.ldtr), &env->ldt);
#ifdef TARGET_X86_64 #ifdef TARGET_X86_64
env->kernelgsbase = x86_ldq_phys(cs, addr + offsetof(struct vmcb, env->kernelgsbase =
save.kernel_gs_base)); cpu_ldq_mmuidx_ra(env,
env->lstar = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.lstar)); addr + offsetof(struct vmcb, save.kernel_gs_base),
env->cstar = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.cstar)); mmu_idx, 0);
env->fmask = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.sfmask)); env->lstar =
cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.lstar),
mmu_idx, 0);
env->cstar =
cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.cstar),
mmu_idx, 0);
env->fmask =
cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sfmask),
mmu_idx, 0);
svm_canonicalization(env, &env->kernelgsbase); svm_canonicalization(env, &env->kernelgsbase);
#endif #endif
env->star = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.star)); env->star =
env->sysenter_cs = x86_ldq_phys(cs, cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.star),
addr + offsetof(struct vmcb, save.sysenter_cs)); mmu_idx, 0);
env->sysenter_esp = x86_ldq_phys(cs, addr + offsetof(struct vmcb, env->sysenter_cs =
save.sysenter_esp)); cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_cs),
env->sysenter_eip = x86_ldq_phys(cs, addr + offsetof(struct vmcb, mmu_idx, 0);
save.sysenter_eip)); env->sysenter_esp =
cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_esp),
mmu_idx, 0);
env->sysenter_eip =
cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_eip),
mmu_idx, 0);
} }
void helper_vmsave(CPUX86State *env, int aflag) void helper_vmsave(CPUX86State *env, int aflag)
{ {
CPUState *cs = env_cpu(env); int mmu_idx = MMU_PHYS_IDX;
target_ulong addr; target_ulong addr;
int prot;
cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0, GETPC()); cpu_svm_check_intercept_param(env, SVM_EXIT_VMSAVE, 0, GETPC());
@ -509,38 +530,36 @@ void helper_vmsave(CPUX86State *env, int aflag)
} }
if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMSAVE, GETPC())) { if (virtual_vm_load_save_enabled(env, SVM_EXIT_VMSAVE, GETPC())) {
addr = get_hphys(cs, addr, MMU_DATA_STORE, &prot); mmu_idx = MMU_NESTED_IDX;
} }
qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmsave! " TARGET_FMT_lx svm_save_seg(env, mmu_idx, addr + offsetof(struct vmcb, save.fs),
"\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
addr, x86_ldq_phys(cs,
addr + offsetof(struct vmcb, save.fs.base)),
env->segs[R_FS].base);
svm_save_seg(env, addr + offsetof(struct vmcb, save.fs),
&env->segs[R_FS]); &env->segs[R_FS]);
svm_save_seg(env, addr + offsetof(struct vmcb, save.gs), svm_save_seg(env, mmu_idx, addr + offsetof(struct vmcb, save.gs),
&env->segs[R_GS]); &env->segs[R_GS]);
svm_save_seg(env, addr + offsetof(struct vmcb, save.tr), svm_save_seg(env, mmu_idx, addr + offsetof(struct vmcb, save.tr),
&env->tr); &env->tr);
svm_save_seg(env, addr + offsetof(struct vmcb, save.ldtr), svm_save_seg(env, mmu_idx, addr + offsetof(struct vmcb, save.ldtr),
&env->ldt); &env->ldt);
#ifdef TARGET_X86_64 #ifdef TARGET_X86_64
x86_stq_phys(cs, addr + offsetof(struct vmcb, save.kernel_gs_base), cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.kernel_gs_base),
env->kernelgsbase); env->kernelgsbase, mmu_idx, 0);
x86_stq_phys(cs, addr + offsetof(struct vmcb, save.lstar), env->lstar); cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.lstar),
x86_stq_phys(cs, addr + offsetof(struct vmcb, save.cstar), env->cstar); env->lstar, mmu_idx, 0);
x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sfmask), env->fmask); cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.cstar),
env->cstar, mmu_idx, 0);
cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sfmask),
env->fmask, mmu_idx, 0);
#endif #endif
x86_stq_phys(cs, addr + offsetof(struct vmcb, save.star), env->star); cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.star),
x86_stq_phys(cs, env->star, mmu_idx, 0);
addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs); cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_cs),
x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sysenter_esp), env->sysenter_cs, mmu_idx, 0);
env->sysenter_esp); cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_esp),
x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sysenter_eip), env->sysenter_esp, mmu_idx, 0);
env->sysenter_eip); cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_eip),
env->sysenter_eip, mmu_idx, 0);
} }
void helper_stgi(CPUX86State *env) void helper_stgi(CPUX86State *env)
@ -720,15 +739,20 @@ void do_vmexit(CPUX86State *env)
env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0); env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0);
} }
env->hflags2 &= ~HF2_NPT_MASK; env->hflags2 &= ~HF2_NPT_MASK;
tlb_flush_by_mmuidx(cs, 1 << MMU_NESTED_IDX);
/* Save the VM state in the vmcb */ /* Save the VM state in the vmcb */
svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.es), svm_save_seg(env, MMU_PHYS_IDX,
env->vm_vmcb + offsetof(struct vmcb, save.es),
&env->segs[R_ES]); &env->segs[R_ES]);
svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.cs), svm_save_seg(env, MMU_PHYS_IDX,
env->vm_vmcb + offsetof(struct vmcb, save.cs),
&env->segs[R_CS]); &env->segs[R_CS]);
svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.ss), svm_save_seg(env, MMU_PHYS_IDX,
env->vm_vmcb + offsetof(struct vmcb, save.ss),
&env->segs[R_SS]); &env->segs[R_SS]);
svm_save_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.ds), svm_save_seg(env, MMU_PHYS_IDX,
env->vm_vmcb + offsetof(struct vmcb, save.ds),
&env->segs[R_DS]); &env->segs[R_DS]);
x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base),
@ -809,14 +833,14 @@ void do_vmexit(CPUX86State *env)
~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK | ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK |
VM_MASK)); VM_MASK));
svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.es), svm_load_seg_cache(env, MMU_PHYS_IDX,
R_ES); env->vm_hsave + offsetof(struct vmcb, save.es), R_ES);
svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.cs), svm_load_seg_cache(env, MMU_PHYS_IDX,
R_CS); env->vm_hsave + offsetof(struct vmcb, save.cs), R_CS);
svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.ss), svm_load_seg_cache(env, MMU_PHYS_IDX,
R_SS); env->vm_hsave + offsetof(struct vmcb, save.ss), R_SS);
svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.ds), svm_load_seg_cache(env, MMU_PHYS_IDX,
R_DS); env->vm_hsave + offsetof(struct vmcb, save.ds), R_DS);
env->eip = x86_ldq_phys(cs, env->eip = x86_ldq_phys(cs,
env->vm_hsave + offsetof(struct vmcb, save.rip)); env->vm_hsave + offsetof(struct vmcb, save.rip));

File diff suppressed because it is too large Load Diff

View File

@ -27,26 +27,34 @@ static void gen_bytepick_d(TCGv dest, TCGv src1, TCGv src2, target_long sa)
tcg_gen_extract2_i64(dest, src1, src2, (64 - sa * 8)); tcg_gen_extract2_i64(dest, src1, src2, (64 - sa * 8));
} }
static void gen_bstrins(TCGv dest, TCGv src1, static bool gen_bstrins(DisasContext *ctx, arg_rr_ms_ls *a,
unsigned int ls, unsigned int len) DisasExtend dst_ext)
{ {
tcg_gen_deposit_tl(dest, dest, src1, ls, len); TCGv src1 = gpr_src(ctx, a->rd, EXT_NONE);
} TCGv src2 = gpr_src(ctx, a->rj, EXT_NONE);
TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
static bool gen_rr_ms_ls(DisasContext *ctx, arg_rr_ms_ls *a,
DisasExtend src_ext, DisasExtend dst_ext,
void (*func)(TCGv, TCGv, unsigned int, unsigned int))
{
TCGv dest = gpr_dst(ctx, a->rd, dst_ext);
TCGv src1 = gpr_src(ctx, a->rj, src_ext);
if (a->ls > a->ms) { if (a->ls > a->ms) {
return false; return false;
} }
func(dest, src1, a->ls, a->ms - a->ls + 1); tcg_gen_deposit_tl(dest, src1, src2, a->ls, a->ms - a->ls + 1);
gen_set_gpr(a->rd, dest, dst_ext); gen_set_gpr(a->rd, dest, dst_ext);
return true;
}
static bool gen_bstrpick(DisasContext *ctx, arg_rr_ms_ls *a,
DisasExtend dst_ext)
{
TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
if (a->ls > a->ms) {
return false;
}
tcg_gen_extract_tl(dest, src1, a->ls, a->ms - a->ls + 1);
gen_set_gpr(a->rd, dest, dst_ext);
return true; return true;
} }
@ -206,7 +214,7 @@ TRANS(maskeqz, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_maskeqz)
TRANS(masknez, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_masknez) TRANS(masknez, gen_rrr, EXT_NONE, EXT_NONE, EXT_NONE, gen_masknez)
TRANS(bytepick_w, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_bytepick_w) TRANS(bytepick_w, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_bytepick_w)
TRANS(bytepick_d, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_bytepick_d) TRANS(bytepick_d, gen_rrr_sa, EXT_NONE, EXT_NONE, gen_bytepick_d)
TRANS(bstrins_w, gen_rr_ms_ls, EXT_NONE, EXT_NONE, gen_bstrins) TRANS(bstrins_w, gen_bstrins, EXT_SIGN)
TRANS(bstrins_d, gen_rr_ms_ls, EXT_NONE, EXT_NONE, gen_bstrins) TRANS(bstrins_d, gen_bstrins, EXT_NONE)
TRANS(bstrpick_w, gen_rr_ms_ls, EXT_NONE, EXT_SIGN, tcg_gen_extract_tl) TRANS(bstrpick_w, gen_bstrpick, EXT_SIGN)
TRANS(bstrpick_d, gen_rr_ms_ls, EXT_NONE, EXT_NONE, tcg_gen_extract_tl) TRANS(bstrpick_d, gen_bstrpick, EXT_NONE)

View File

@ -97,9 +97,9 @@ TRANS(fmadd_s, gen_muladd, gen_helper_fmuladd_s, 0)
TRANS(fmadd_d, gen_muladd, gen_helper_fmuladd_d, 0) TRANS(fmadd_d, gen_muladd, gen_helper_fmuladd_d, 0)
TRANS(fmsub_s, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_c) TRANS(fmsub_s, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_c)
TRANS(fmsub_d, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_c) TRANS(fmsub_d, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_c)
TRANS(fnmadd_s, gen_muladd, gen_helper_fmuladd_s, TRANS(fnmadd_s, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_result)
float_muladd_negate_product | float_muladd_negate_c) TRANS(fnmadd_d, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_result)
TRANS(fnmadd_d, gen_muladd, gen_helper_fmuladd_d, TRANS(fnmsub_s, gen_muladd, gen_helper_fmuladd_s,
float_muladd_negate_product | float_muladd_negate_c) float_muladd_negate_c | float_muladd_negate_result)
TRANS(fnmsub_s, gen_muladd, gen_helper_fmuladd_s, float_muladd_negate_product) TRANS(fnmsub_d, gen_muladd, gen_helper_fmuladd_d,
TRANS(fnmsub_d, gen_muladd, gen_helper_fmuladd_d, float_muladd_negate_product) float_muladd_negate_c | float_muladd_negate_result)

View File

@ -1247,6 +1247,12 @@ static void powerpc_excp_booke(PowerPCCPU *cpu, int excp)
case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable/VPU */ case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable/VPU */
env->spr[SPR_BOOKE_ESR] = ESR_SPV; env->spr[SPR_BOOKE_ESR] = ESR_SPV;
break; break;
case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
break;
case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
srr0 = SPR_BOOKE_CSRR0;
srr1 = SPR_BOOKE_CSRR1;
break;
case POWERPC_EXCP_RESET: /* System reset exception */ case POWERPC_EXCP_RESET: /* System reset exception */
if (FIELD_EX64(env->msr, MSR, POW)) { if (FIELD_EX64(env->msr, MSR, POW)) {
cpu_abort(cs, "Trying to deliver power-saving system reset " cpu_abort(cs, "Trying to deliver power-saving system reset "

View File

@ -810,7 +810,6 @@ static void gen_##name(DisasContext *ctx) \
gen_helper_##name(ignored, cpu_env, xt, xa, xb); \ gen_helper_##name(ignored, cpu_env, xt, xa, xb); \
tcg_temp_free_i32(ignored); \ tcg_temp_free_i32(ignored); \
} \ } \
gen_helper_float_check_status(cpu_env); \
tcg_temp_free_ptr(xt); \ tcg_temp_free_ptr(xt); \
tcg_temp_free_ptr(xa); \ tcg_temp_free_ptr(xa); \
tcg_temp_free_ptr(xb); \ tcg_temp_free_ptr(xb); \

View File

@ -107,7 +107,7 @@ run-test-mmx: QEMU_OPTS += -cpu max
run-plugin-test-mmx: QEMU_OPTS += -cpu max run-plugin-test-mmx: QEMU_OPTS += -cpu max
test-mmx: test-mmx.h test-mmx: test-mmx.h
test-avx: CFLAGS += -masm=intel -O -I. test-avx: CFLAGS += -mavx -masm=intel -O -I.
run-test-avx: QEMU_OPTS += -cpu max run-test-avx: QEMU_OPTS += -cpu max
run-plugin-test-avx: QEMU_OPTS += -cpu max run-plugin-test-avx: QEMU_OPTS += -cpu max
test-avx: test-avx.h test-avx: test-avx.h

View File

@ -6,18 +6,18 @@
typedef void (*testfn)(void); typedef void (*testfn)(void);
typedef struct { typedef struct {
uint64_t q0, q1; uint64_t q0, q1, q2, q3;
} __attribute__((aligned(16))) v2di; } __attribute__((aligned(32))) v4di;
typedef struct { typedef struct {
uint64_t mm[8]; uint64_t mm[8];
v2di xmm[16]; v4di ymm[16];
uint64_t r[16]; uint64_t r[16];
uint64_t flags; uint64_t flags;
uint32_t ff; uint32_t ff;
uint64_t pad; uint64_t pad;
v2di mem[4]; v4di mem[4];
v2di mem0[4]; v4di mem0[4];
} reg_state; } reg_state;
typedef struct { typedef struct {
@ -31,20 +31,20 @@ reg_state initI;
reg_state initF32; reg_state initF32;
reg_state initF64; reg_state initF64;
static void dump_xmm(const char *name, int n, const v2di *r, int ff) static void dump_ymm(const char *name, int n, const v4di *r, int ff)
{ {
printf("%s%d = %016lx %016lx\n", printf("%s%d = %016lx %016lx %016lx %016lx\n",
name, n, r->q1, r->q0); name, n, r->q3, r->q2, r->q1, r->q0);
if (ff == 64) { if (ff == 64) {
double v[2]; double v[4];
memcpy(v, r, sizeof(v)); memcpy(v, r, sizeof(v));
printf(" %16g %16g\n", printf(" %16g %16g %16g %16g\n",
v[1], v[0]);
} else if (ff == 32) {
float v[4];
memcpy(v, r, sizeof(v));
printf(" %8g %8g %8g %8g\n",
v[3], v[2], v[1], v[0]); v[3], v[2], v[1], v[0]);
} else if (ff == 32) {
float v[8];
memcpy(v, r, sizeof(v));
printf(" %8g %8g %8g %8g %8g %8g %8g %8g\n",
v[7], v[6], v[5], v[4], v[3], v[2], v[1], v[0]);
} }
} }
@ -53,10 +53,10 @@ static void dump_regs(reg_state *s)
int i; int i;
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
dump_xmm("xmm", i, &s->xmm[i], 0); dump_ymm("ymm", i, &s->ymm[i], 0);
} }
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
dump_xmm("mem", i, &s->mem0[i], 0); dump_ymm("mem", i, &s->mem0[i], 0);
} }
} }
@ -74,13 +74,13 @@ static void compare_state(const reg_state *a, const reg_state *b)
} }
} }
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
if (memcmp(&a->xmm[i], &b->xmm[i], 16)) { if (memcmp(&a->ymm[i], &b->ymm[i], 32)) {
dump_xmm("xmm", i, &b->xmm[i], a->ff); dump_ymm("ymm", i, &b->ymm[i], a->ff);
} }
} }
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
if (memcmp(&a->mem0[i], &a->mem[i], 16)) { if (memcmp(&a->mem0[i], &a->mem[i], 32)) {
dump_xmm("mem", i, &a->mem[i], a->ff); dump_ymm("mem", i, &a->mem[i], a->ff);
} }
} }
if (a->flags != b->flags) { if (a->flags != b->flags) {
@ -89,9 +89,9 @@ static void compare_state(const reg_state *a, const reg_state *b)
} }
#define LOADMM(r, o) "movq " #r ", " #o "[%0]\n\t" #define LOADMM(r, o) "movq " #r ", " #o "[%0]\n\t"
#define LOADXMM(r, o) "movdqa " #r ", " #o "[%0]\n\t" #define LOADYMM(r, o) "vmovdqa " #r ", " #o "[%0]\n\t"
#define STOREMM(r, o) "movq " #o "[%1], " #r "\n\t" #define STOREMM(r, o) "movq " #o "[%1], " #r "\n\t"
#define STOREXMM(r, o) "movdqa " #o "[%1], " #r "\n\t" #define STOREYMM(r, o) "vmovdqa " #o "[%1], " #r "\n\t"
#define MMREG(F) \ #define MMREG(F) \
F(mm0, 0x00) \ F(mm0, 0x00) \
F(mm1, 0x08) \ F(mm1, 0x08) \
@ -101,39 +101,39 @@ static void compare_state(const reg_state *a, const reg_state *b)
F(mm5, 0x28) \ F(mm5, 0x28) \
F(mm6, 0x30) \ F(mm6, 0x30) \
F(mm7, 0x38) F(mm7, 0x38)
#define XMMREG(F) \ #define YMMREG(F) \
F(xmm0, 0x040) \ F(ymm0, 0x040) \
F(xmm1, 0x050) \ F(ymm1, 0x060) \
F(xmm2, 0x060) \ F(ymm2, 0x080) \
F(xmm3, 0x070) \ F(ymm3, 0x0a0) \
F(xmm4, 0x080) \ F(ymm4, 0x0c0) \
F(xmm5, 0x090) \ F(ymm5, 0x0e0) \
F(xmm6, 0x0a0) \ F(ymm6, 0x100) \
F(xmm7, 0x0b0) \ F(ymm7, 0x120) \
F(xmm8, 0x0c0) \ F(ymm8, 0x140) \
F(xmm9, 0x0d0) \ F(ymm9, 0x160) \
F(xmm10, 0x0e0) \ F(ymm10, 0x180) \
F(xmm11, 0x0f0) \ F(ymm11, 0x1a0) \
F(xmm12, 0x100) \ F(ymm12, 0x1c0) \
F(xmm13, 0x110) \ F(ymm13, 0x1e0) \
F(xmm14, 0x120) \ F(ymm14, 0x200) \
F(xmm15, 0x130) F(ymm15, 0x220)
#define LOADREG(r, o) "mov " #r ", " #o "[rax]\n\t" #define LOADREG(r, o) "mov " #r ", " #o "[rax]\n\t"
#define STOREREG(r, o) "mov " #o "[rax], " #r "\n\t" #define STOREREG(r, o) "mov " #o "[rax], " #r "\n\t"
#define REG(F) \ #define REG(F) \
F(rbx, 0x148) \ F(rbx, 0x248) \
F(rcx, 0x150) \ F(rcx, 0x250) \
F(rdx, 0x158) \ F(rdx, 0x258) \
F(rsi, 0x160) \ F(rsi, 0x260) \
F(rdi, 0x168) \ F(rdi, 0x268) \
F(r8, 0x180) \ F(r8, 0x280) \
F(r9, 0x188) \ F(r9, 0x288) \
F(r10, 0x190) \ F(r10, 0x290) \
F(r11, 0x198) \ F(r11, 0x298) \
F(r12, 0x1a0) \ F(r12, 0x2a0) \
F(r13, 0x1a8) \ F(r13, 0x2a8) \
F(r14, 0x1b0) \ F(r14, 0x2b0) \
F(r15, 0x1b8) \ F(r15, 0x2b8) \
static void run_test(const TestDef *t) static void run_test(const TestDef *t)
{ {
@ -143,7 +143,7 @@ static void run_test(const TestDef *t)
printf("%5d %s\n", t->n, t->s); printf("%5d %s\n", t->n, t->s);
asm volatile( asm volatile(
MMREG(LOADMM) MMREG(LOADMM)
XMMREG(LOADXMM) YMMREG(LOADYMM)
"sub rsp, 128\n\t" "sub rsp, 128\n\t"
"push rax\n\t" "push rax\n\t"
"push rbx\n\t" "push rbx\n\t"
@ -156,26 +156,26 @@ static void run_test(const TestDef *t)
"pop rbx\n\t" "pop rbx\n\t"
"shr rbx, 8\n\t" "shr rbx, 8\n\t"
"shl rbx, 8\n\t" "shl rbx, 8\n\t"
"mov rcx, 0x1c0[rax]\n\t" "mov rcx, 0x2c0[rax]\n\t"
"and rcx, 0xff\n\t" "and rcx, 0xff\n\t"
"or rbx, rcx\n\t" "or rbx, rcx\n\t"
"push rbx\n\t" "push rbx\n\t"
"popf\n\t" "popf\n\t"
REG(LOADREG) REG(LOADREG)
"mov rax, 0x140[rax]\n\t" "mov rax, 0x240[rax]\n\t"
"call [rsp]\n\t" "call [rsp]\n\t"
"mov [rsp], rax\n\t" "mov [rsp], rax\n\t"
"mov rax, 8[rsp]\n\t" "mov rax, 8[rsp]\n\t"
REG(STOREREG) REG(STOREREG)
"mov rbx, [rsp]\n\t" "mov rbx, [rsp]\n\t"
"mov 0x140[rax], rbx\n\t" "mov 0x240[rax], rbx\n\t"
"mov rbx, 0\n\t" "mov rbx, 0\n\t"
"mov 0x170[rax], rbx\n\t" "mov 0x270[rax], rbx\n\t"
"mov 0x178[rax], rbx\n\t" "mov 0x278[rax], rbx\n\t"
"pushf\n\t" "pushf\n\t"
"pop rbx\n\t" "pop rbx\n\t"
"and rbx, 0xff\n\t" "and rbx, 0xff\n\t"
"mov 0x1c0[rax], rbx\n\t" "mov 0x2c0[rax], rbx\n\t"
"add rsp, 16\n\t" "add rsp, 16\n\t"
"pop rdx\n\t" "pop rdx\n\t"
"pop rcx\n\t" "pop rcx\n\t"
@ -183,15 +183,15 @@ static void run_test(const TestDef *t)
"pop rax\n\t" "pop rax\n\t"
"add rsp, 128\n\t" "add rsp, 128\n\t"
MMREG(STOREMM) MMREG(STOREMM)
XMMREG(STOREXMM) YMMREG(STOREYMM)
: : "r"(init), "r"(&result), "r"(t->fn) : : "r"(init), "r"(&result), "r"(t->fn)
: "memory", "cc", : "memory", "cc",
"rsi", "rdi", "rsi", "rdi",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
"mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
"xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5",
"xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11", "ymm6", "ymm7", "ymm8", "ymm9", "ymm10", "ymm11",
"xmm12", "xmm13", "xmm14", "xmm15" "ymm12", "ymm13", "ymm14", "ymm15"
); );
compare_state(init, &result); compare_state(init, &result);
} }
@ -223,22 +223,30 @@ static void run_all(void)
float val_f32[] = {2.0, -1.0, 4.8, 0.8, 3, -42.0, 5e6, 7.5, 8.3}; float val_f32[] = {2.0, -1.0, 4.8, 0.8, 3, -42.0, 5e6, 7.5, 8.3};
double val_f64[] = {2.0, -1.0, 4.8, 0.8, 3, -42.0, 5e6, 7.5}; double val_f64[] = {2.0, -1.0, 4.8, 0.8, 3, -42.0, 5e6, 7.5};
v2di val_i64[] = { v4di val_i64[] = {
{0x3d6b3b6a9e4118f2lu, 0x355ae76d2774d78clu}, {0x3d6b3b6a9e4118f2lu, 0x355ae76d2774d78clu,
{0xd851c54a56bf1f29lu, 0x4a84d1d50bf4c4fflu}, 0xac3ff76c4daa4b28lu, 0xe7fabd204cb54083lu},
{0x5826475e2c5fd799lu, 0xfd32edc01243f5e9lu}, {0xd851c54a56bf1f29lu, 0x4a84d1d50bf4c4fflu,
0x56621e553d52b56clu, 0xd0069553da8f584alu},
{0x5826475e2c5fd799lu, 0xfd32edc01243f5e9lu,
0x738ba2c66d3fe126lu, 0x5707219c6e6c26b4lu},
}; };
v2di deadbeef = {0xa5a5a5a5deadbeefull, 0xa5a5a5a5deadbeefull}; v4di deadbeef = {0xa5a5a5a5deadbeefull, 0xa5a5a5a5deadbeefull,
v2di indexq = {0x000000000000001full, 0x000000000000008full}; 0xa5a5a5a5deadbeefull, 0xa5a5a5a5deadbeefull};
v2di indexd = {0x00000002000000efull, 0xfffffff500000010ull}; v4di indexq = {0x000000000000001full, 0x000000000000008full,
0xffffffffffffffffull, 0xffffffffffffff5full};
v4di indexd = {0x00000002000000efull, 0xfffffff500000010ull,
0x0000000afffffff0ull, 0x000000000000000eull};
void init_f32reg(v2di *r) v4di gather_mem[0x20];
void init_f32reg(v4di *r)
{ {
static int n; static int n;
float v[4]; float v[8];
int i; int i;
for (i = 0; i < 4; i++) { for (i = 0; i < 8; i++) {
v[i] = val_f32[n++]; v[i] = val_f32[n++];
if (n == ARRAY_LEN(val_f32)) { if (n == ARRAY_LEN(val_f32)) {
n = 0; n = 0;
@ -247,12 +255,12 @@ void init_f32reg(v2di *r)
memcpy(r, v, sizeof(*r)); memcpy(r, v, sizeof(*r));
} }
void init_f64reg(v2di *r) void init_f64reg(v4di *r)
{ {
static int n; static int n;
double v[2]; double v[4];
int i; int i;
for (i = 0; i < 2; i++) { for (i = 0; i < 4; i++) {
v[i] = val_f64[n++]; v[i] = val_f64[n++];
if (n == ARRAY_LEN(val_f64)) { if (n == ARRAY_LEN(val_f64)) {
n = 0; n = 0;
@ -261,13 +269,15 @@ void init_f64reg(v2di *r)
memcpy(r, v, sizeof(*r)); memcpy(r, v, sizeof(*r));
} }
void init_intreg(v2di *r) void init_intreg(v4di *r)
{ {
static uint64_t mask; static uint64_t mask;
static int n; static int n;
r->q0 = val_i64[n].q0 ^ mask; r->q0 = val_i64[n].q0 ^ mask;
r->q1 = val_i64[n].q1 ^ mask; r->q1 = val_i64[n].q1 ^ mask;
r->q2 = val_i64[n].q2 ^ mask;
r->q3 = val_i64[n].q3 ^ mask;
n++; n++;
if (n == ARRAY_LEN(val_i64)) { if (n == ARRAY_LEN(val_i64)) {
n = 0; n = 0;
@ -280,46 +290,53 @@ static void init_all(reg_state *s)
int i; int i;
s->r[3] = (uint64_t)&s->mem[0]; /* rdx */ s->r[3] = (uint64_t)&s->mem[0]; /* rdx */
s->r[4] = (uint64_t)&gather_mem[ARRAY_LEN(gather_mem) / 2]; /* rsi */
s->r[5] = (uint64_t)&s->mem[2]; /* rdi */ s->r[5] = (uint64_t)&s->mem[2]; /* rdi */
s->flags = 2; s->flags = 2;
for (i = 0; i < 8; i++) { for (i = 0; i < 16; i++) {
s->xmm[i] = deadbeef; s->ymm[i] = deadbeef;
} }
s->xmm[13] = indexd; s->ymm[13] = indexd;
s->xmm[14] = indexq; s->ymm[14] = indexq;
for (i = 0; i < 2; i++) { for (i = 0; i < 4; i++) {
s->mem0[i] = deadbeef; s->mem0[i] = deadbeef;
} }
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int i;
init_all(&initI); init_all(&initI);
init_intreg(&initI.xmm[10]); init_intreg(&initI.ymm[10]);
init_intreg(&initI.xmm[11]); init_intreg(&initI.ymm[11]);
init_intreg(&initI.xmm[12]); init_intreg(&initI.ymm[12]);
init_intreg(&initI.mem0[1]); init_intreg(&initI.mem0[1]);
printf("Int:\n"); printf("Int:\n");
dump_regs(&initI); dump_regs(&initI);
init_all(&initF32); init_all(&initF32);
init_f32reg(&initF32.xmm[10]); init_f32reg(&initF32.ymm[10]);
init_f32reg(&initF32.xmm[11]); init_f32reg(&initF32.ymm[11]);
init_f32reg(&initF32.xmm[12]); init_f32reg(&initF32.ymm[12]);
init_f32reg(&initF32.mem0[1]); init_f32reg(&initF32.mem0[1]);
initF32.ff = 32; initF32.ff = 32;
printf("F32:\n"); printf("F32:\n");
dump_regs(&initF32); dump_regs(&initF32);
init_all(&initF64); init_all(&initF64);
init_f64reg(&initF64.xmm[10]); init_f64reg(&initF64.ymm[10]);
init_f64reg(&initF64.xmm[11]); init_f64reg(&initF64.ymm[11]);
init_f64reg(&initF64.xmm[12]); init_f64reg(&initF64.ymm[12]);
init_f64reg(&initF64.mem0[1]); init_f64reg(&initF64.mem0[1]);
initF64.ff = 64; initF64.ff = 64;
printf("F64:\n"); printf("F64:\n");
dump_regs(&initF64); dump_regs(&initF64);
for (i = 0; i < ARRAY_LEN(gather_mem); i++) {
init_intreg(&gather_mem[i]);
}
if (argc > 1) { if (argc > 1) {
int n = atoi(argv[1]); int n = atoi(argv[1]);
run_test(&test_table[n]); run_test(&test_table[n]);

View File

@ -8,6 +8,7 @@ from fnmatch import fnmatch
archs = [ archs = [
"SSE", "SSE2", "SSE3", "SSSE3", "SSE4_1", "SSE4_2", "SSE", "SSE2", "SSE3", "SSSE3", "SSE4_1", "SSE4_2",
"AES", "AVX", "AVX2", "AES+AVX", "VAES+AVX",
] ]
ignore = set(["FISTTP", ignore = set(["FISTTP",
@ -42,7 +43,7 @@ imask = {
'vROUND[PS][SD]': 0x7, 'vROUND[PS][SD]': 0x7,
'vSHUFPD': 0x0f, 'vSHUFPD': 0x0f,
'vSHUFPS': 0xff, 'vSHUFPS': 0xff,
'vAESKEYGENASSIST': 0, 'vAESKEYGENASSIST': 0xff,
'VEXTRACT[FI]128': 0x01, 'VEXTRACT[FI]128': 0x01,
'VINSERT[FI]128': 0x01, 'VINSERT[FI]128': 0x01,
'VPBLENDD': 0xff, 'VPBLENDD': 0xff,
@ -85,7 +86,7 @@ def mem_w(w):
else: else:
raise Exception() raise Exception()
return t + " PTR 16[rdx]" return t + " PTR 32[rdx]"
class XMMArg(): class XMMArg():
isxmm = True isxmm = True