mirror of
https://github.com/xemu-project/xemu.git
synced 2025-02-17 02:29:12 +00:00
* configure: don't enable firmware for targets that are not built
* configure: don't use strings(1) * scsi, target/i386: switch from device_legacy_reset() to device_cold_reset() * target/i386: AVX support for TCG * target/i386: fix SynIC SINT assertion failure on guest reset * target/i386: Use atomic operations for pte updates and other cleanups * tests/tcg: extend SSE tests to AVX * virtio-scsi: send "REPORTED LUNS CHANGED" sense data upon disk hotplug events -----BEGIN PGP SIGNATURE----- iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmNOlOcUHHBib256aW5p QHJlZGhhdC5jb20ACgkQv/vSX3jHroNuvwgAj/Z5pI9KU33XiWKFR3bZf2lHh21P xmTzNtPmnP1WHDY1DNug/UB+BLg3c+carpTf5n3B8aKI4X3FfxGSJvYlXy4BONFD XqYMH3OZB5GaR8Wza9trNYjDs/9hOZus/0R6Hqdl/T38PlMjf8mmayULJIGdcFcJ WJvITVntbcCwwbpyJbRC5BNigG8ZXTNRoKBgtFVGz6Ox+n0YydwKX5qU5J7xRfCU lW41LjZ0Fk5lonH16+xuS4WD5EyrNt8cMKCGsxnyxhI7nehe/OGnYr9l+xZJclrh inQlSwJv0IpUJcrGCI4Xugwux4Z7ZXv3JQ37FzsdZcv/ZXpGonXMeXNJ9A== =o6x7 -----END PGP SIGNATURE----- Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging * configure: don't enable firmware for targets that are not built * configure: don't use strings(1) * scsi, target/i386: switch from device_legacy_reset() to device_cold_reset() * target/i386: AVX support for TCG * target/i386: fix SynIC SINT assertion failure on guest reset * target/i386: Use atomic operations for pte updates and other cleanups * tests/tcg: extend SSE tests to AVX * virtio-scsi: send "REPORTED LUNS CHANGED" sense data upon disk hotplug events # -----BEGIN PGP SIGNATURE----- # # iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmNOlOcUHHBib256aW5p # QHJlZGhhdC5jb20ACgkQv/vSX3jHroNuvwgAj/Z5pI9KU33XiWKFR3bZf2lHh21P # xmTzNtPmnP1WHDY1DNug/UB+BLg3c+carpTf5n3B8aKI4X3FfxGSJvYlXy4BONFD # XqYMH3OZB5GaR8Wza9trNYjDs/9hOZus/0R6Hqdl/T38PlMjf8mmayULJIGdcFcJ # WJvITVntbcCwwbpyJbRC5BNigG8ZXTNRoKBgtFVGz6Ox+n0YydwKX5qU5J7xRfCU # lW41LjZ0Fk5lonH16+xuS4WD5EyrNt8cMKCGsxnyxhI7nehe/OGnYr9l+xZJclrh # inQlSwJv0IpUJcrGCI4Xugwux4Z7ZXv3JQ37FzsdZcv/ZXpGonXMeXNJ9A== # =o6x7 # -----END PGP SIGNATURE----- # gpg: Signature made Tue 18 Oct 2022 07:58:31 EDT # gpg: using RSA key F13338574B662389866C7682BFFBD25F78C7AE83 # gpg: issuer "pbonzini@redhat.com" # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" [full] # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" [full] # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * tag 'for-upstream' of https://gitlab.com/bonzini/qemu: (53 commits) target/i386: remove old SSE decoder target/i386: move 3DNow to the new decoder tests/tcg: extend SSE tests to AVX target/i386: Enable AVX cpuid bits when using TCG target/i386: implement VLDMXCSR/VSTMXCSR target/i386: implement XSAVE and XRSTOR of AVX registers target/i386: reimplement 0x0f 0x28-0x2f, add AVX target/i386: reimplement 0x0f 0x10-0x17, add AVX target/i386: reimplement 0x0f 0xc2, 0xc4-0xc6, add AVX target/i386: reimplement 0x0f 0x38, add AVX target/i386: Use tcg gvec ops for pmovmskb target/i386: reimplement 0x0f 0x3a, add AVX target/i386: clarify (un)signedness of immediates from 0F3Ah opcodes target/i386: reimplement 0x0f 0xd0-0xd7, 0xe0-0xe7, 0xf0-0xf7, add AVX target/i386: reimplement 0x0f 0x70-0x77, add AVX target/i386: reimplement 0x0f 0x78-0x7f, add AVX target/i386: reimplement 0x0f 0x50-0x5f, add AVX target/i386: reimplement 0x0f 0xd8-0xdf, 0xe8-0xef, 0xf8-0xff, add AVX target/i386: reimplement 0x0f 0x60-0x6f, add AVX target/i386: Introduce 256-bit vector helpers ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
214a8da236
55
configure
vendored
55
configure
vendored
@ -1423,30 +1423,31 @@ if test "$tcg" = "enabled"; then
|
||||
git_submodules="$git_submodules tests/fp/berkeley-softfloat-3"
|
||||
fi
|
||||
|
||||
# ---
|
||||
##########################################
|
||||
# big/little endian test
|
||||
cat > $TMPC << EOF
|
||||
#include <stdio.h>
|
||||
short big_endian[] = { 0x4269, 0x4765, 0x4e64, 0x4961, 0x4e00, 0, };
|
||||
short little_endian[] = { 0x694c, 0x7454, 0x654c, 0x6e45, 0x6944, 0x6e41, 0, };
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return printf("%s %s\n", (char *)big_endian, (char *)little_endian);
|
||||
}
|
||||
#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
# error LITTLE
|
||||
#endif
|
||||
int main(void) { return 0; }
|
||||
EOF
|
||||
|
||||
if compile_prog ; then
|
||||
if strings -a $TMPE | grep -q BiGeNdIaN ; then
|
||||
bigendian="yes"
|
||||
elif strings -a $TMPE | grep -q LiTtLeEnDiAn ; then
|
||||
bigendian="no"
|
||||
else
|
||||
echo big/little test failed
|
||||
exit 1
|
||||
fi
|
||||
if ! compile_prog ; then
|
||||
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
|
||||
echo big/little test failed
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
##########################################
|
||||
@ -1841,6 +1842,16 @@ compute_target_variable() {
|
||||
fi
|
||||
}
|
||||
|
||||
have_target() {
|
||||
for i; do
|
||||
case " $target_list " in
|
||||
*" $i "*) return 0;;
|
||||
*) ;;
|
||||
esac
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# probe_target_compiler TARGET
|
||||
#
|
||||
# Look for a compiler for the given target, either native or cross.
|
||||
@ -2261,8 +2272,9 @@ echo "# Automatically generated by configure - do not modify" > Makefile.prereqs
|
||||
|
||||
# Mac OS X ships with a broken assembler
|
||||
roms=
|
||||
if test "$targetos" != "darwin" && test "$targetos" != "sunos" && \
|
||||
test "$targetos" != "haiku" && test "$softmmu" = yes && \
|
||||
if have_target i386-softmmu x86_64-softmmu && \
|
||||
test "$targetos" != "darwin" && test "$targetos" != "sunos" && \
|
||||
test "$targetos" != "haiku" && \
|
||||
probe_target_compiler i386-softmmu; then
|
||||
roms="pc-bios/optionrom"
|
||||
config_mak=pc-bios/optionrom/config.mak
|
||||
@ -2271,7 +2283,8 @@ if test "$targetos" != "darwin" && test "$targetos" != "sunos" && \
|
||||
write_target_makefile >> $config_mak
|
||||
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"
|
||||
config_mak=pc-bios/vof/config.mak
|
||||
echo "# Automatically generated by configure - do not modify" > $config_mak
|
||||
@ -2281,7 +2294,7 @@ fi
|
||||
|
||||
# Only build s390-ccw bios if the compiler has -march=z900 or -march=z10
|
||||
# (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
|
||||
do_compiler "$target_cc" $target_cc_cflags -march=z900 -o $TMPO -c $TMPC
|
||||
has_z900=$?
|
||||
|
@ -485,9 +485,7 @@ static void microvm_machine_reset(MachineState *machine)
|
||||
CPU_FOREACH(cs) {
|
||||
cpu = X86_CPU(cs);
|
||||
|
||||
if (cpu->apic_state) {
|
||||
device_legacy_reset(cpu->apic_state);
|
||||
}
|
||||
x86_cpu_after_reset(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,6 +92,7 @@
|
||||
#include "hw/virtio/virtio-mem-pci.h"
|
||||
#include "hw/mem/memory-device.h"
|
||||
#include "sysemu/replay.h"
|
||||
#include "target/i386/cpu.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "e820_memory_layout.h"
|
||||
#include "fw_cfg.h"
|
||||
@ -1859,9 +1860,7 @@ static void pc_machine_reset(MachineState *machine)
|
||||
CPU_FOREACH(cs) {
|
||||
cpu = X86_CPU(cs);
|
||||
|
||||
if (cpu->apic_state) {
|
||||
device_legacy_reset(cpu->apic_state);
|
||||
}
|
||||
x86_cpu_after_reset(cpu);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -941,7 +941,7 @@ static void esp_soft_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)
|
||||
|
@ -1868,7 +1868,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
|
||||
}
|
||||
if (val & LSI_SCNTL1_RST) {
|
||||
if (!(s->sstat0 & LSI_SSTAT0_RST)) {
|
||||
qbus_reset_all(BUS(&s->bus));
|
||||
bus_cold_reset(BUS(&s->bus));
|
||||
s->sstat0 |= LSI_SSTAT0_RST;
|
||||
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);
|
||||
}
|
||||
if (val & LSI_ISTAT0_SRST) {
|
||||
qdev_reset_all(DEVICE(s));
|
||||
device_cold_reset(DEVICE(s));
|
||||
}
|
||||
break;
|
||||
case 0x16: /* MBOX0 */
|
||||
|
@ -1484,7 +1484,7 @@ static int megasas_cluster_reset_ld(MegasasState *s, MegasasCmd *cmd)
|
||||
MegasasCmd *tmp_cmd = &s->frames[i];
|
||||
if (tmp_cmd->req && tmp_cmd->req->dev->id == target_id) {
|
||||
SCSIDevice *d = tmp_cmd->req->dev;
|
||||
qdev_reset_all(&d->qdev);
|
||||
device_cold_reset(&d->qdev);
|
||||
}
|
||||
}
|
||||
return MFI_STAT_OK;
|
||||
|
@ -522,7 +522,7 @@ reply_maybe_async:
|
||||
reply.ResponseCode = MPI_SCSITASKMGMT_RSP_TM_INVALID_LUN;
|
||||
goto out;
|
||||
}
|
||||
qdev_reset_all(&sdev->qdev);
|
||||
device_cold_reset(&sdev->qdev);
|
||||
break;
|
||||
|
||||
case MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
|
||||
@ -538,13 +538,13 @@ reply_maybe_async:
|
||||
QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) {
|
||||
sdev = SCSI_DEVICE(kid->child);
|
||||
if (sdev->channel == 0 && sdev->id == req->TargetID) {
|
||||
qdev_reset_all(kid->child);
|
||||
device_cold_reset(kid->child);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS:
|
||||
qbus_reset_all(BUS(&s->bus));
|
||||
bus_cold_reset(BUS(&s->bus));
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -807,7 +807,7 @@ static void mptsas_soft_reset(MPTSASState *s)
|
||||
s->intr_mask = MPI_HIM_DIM | MPI_HIM_RIM;
|
||||
mptsas_update_interrupt(s);
|
||||
|
||||
qbus_reset_all(BUS(&s->bus));
|
||||
bus_cold_reset(BUS(&s->bus));
|
||||
s->intr_status = 0;
|
||||
s->intr_mask = save_mask;
|
||||
|
||||
|
@ -1616,6 +1616,24 @@ static int scsi_ua_precedence(SCSISense sense)
|
||||
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)
|
||||
{
|
||||
int prec1, prec2;
|
||||
|
@ -865,7 +865,7 @@ static int vscsi_process_tsk_mgmt(VSCSIState *s, vscsi_req *req)
|
||||
break;
|
||||
}
|
||||
|
||||
qdev_reset_all(&d->qdev);
|
||||
device_cold_reset(&d->qdev);
|
||||
break;
|
||||
|
||||
case SRP_TSK_ABORT_TASK_SET:
|
||||
|
@ -365,7 +365,7 @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
|
||||
goto incorrect_lun;
|
||||
}
|
||||
s->resetting++;
|
||||
qdev_reset_all(&d->qdev);
|
||||
device_cold_reset(&d->qdev);
|
||||
s->resetting--;
|
||||
break;
|
||||
|
||||
@ -417,7 +417,7 @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
|
||||
QTAILQ_FOREACH_RCU(kid, &s->bus.qbus.children, sibling) {
|
||||
SCSIDevice *d1 = SCSI_DEVICE(kid->child);
|
||||
if (d1->channel == 0 && d1->id == target) {
|
||||
qdev_reset_all(&d1->qdev);
|
||||
device_cold_reset(&d1->qdev);
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
@ -831,7 +831,7 @@ static void virtio_scsi_reset(VirtIODevice *vdev)
|
||||
|
||||
assert(!s->dataplane_started);
|
||||
s->resetting++;
|
||||
qbus_reset_all(BUS(&s->bus));
|
||||
bus_cold_reset(BUS(&s->bus));
|
||||
s->resetting--;
|
||||
|
||||
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_T_TRANSPORT_RESET,
|
||||
VIRTIO_SCSI_EVT_RESET_RESCAN);
|
||||
scsi_bus_set_ua(&s->bus, SENSE_CODE(REPORTED_LUNS_CHANGED));
|
||||
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_T_TRANSPORT_RESET,
|
||||
VIRTIO_SCSI_EVT_RESET_REMOVED);
|
||||
scsi_bus_set_ua(&s->bus, SENSE_CODE(REPORTED_LUNS_CHANGED));
|
||||
virtio_scsi_release(s);
|
||||
}
|
||||
|
||||
|
@ -445,7 +445,7 @@ static void
|
||||
pvscsi_reset_adapter(PVSCSIState *s)
|
||||
{
|
||||
s->resetting++;
|
||||
qbus_reset_all(BUS(&s->bus));
|
||||
bus_cold_reset(BUS(&s->bus));
|
||||
s->resetting--;
|
||||
pvscsi_process_completion_queue(s);
|
||||
assert(QTAILQ_EMPTY(&s->pending_queue));
|
||||
@ -880,7 +880,7 @@ pvscsi_on_cmd_reset_device(PVSCSIState *s)
|
||||
|
||||
if (sdev != NULL) {
|
||||
s->resetting++;
|
||||
device_legacy_reset(&sdev->qdev);
|
||||
device_cold_reset(&sdev->qdev);
|
||||
s->resetting--;
|
||||
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");
|
||||
|
||||
s->resetting++;
|
||||
qbus_reset_all(BUS(&s->bus));
|
||||
bus_cold_reset(BUS(&s->bus));
|
||||
s->resetting--;
|
||||
return PVSCSI_COMMAND_PROCESSING_SUCCEEDED;
|
||||
}
|
||||
|
@ -186,6 +186,7 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk,
|
||||
BlockdevOnError rerror,
|
||||
BlockdevOnError werror,
|
||||
const char *serial, Error **errp);
|
||||
void scsi_bus_set_ua(SCSIBus *bus, SCSISense sense);
|
||||
void scsi_bus_legacy_handle_cmdline(SCSIBus *bus);
|
||||
void scsi_legacy_handle_cmdline(void);
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
# define TARGET_VIRT_ADDR_SPACE_BITS 32
|
||||
#endif
|
||||
#define TARGET_PAGE_BITS 12
|
||||
#define NB_MMU_MODES 3
|
||||
#define NB_MMU_MODES 5
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
# define TARGET_TB_PCREL 1
|
||||
|
@ -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_XSAVE | /* CPUID_EXT_OSXSAVE is dynamic */ \
|
||||
CPUID_EXT_MOVBE | CPUID_EXT_AES | CPUID_EXT_HYPERVISOR | \
|
||||
CPUID_EXT_RDRAND)
|
||||
CPUID_EXT_RDRAND | CPUID_EXT_AVX)
|
||||
/* missing:
|
||||
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_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 */
|
||||
|
||||
#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_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_ERMS)
|
||||
CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_AVX2)
|
||||
/* 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_RDSEED */
|
||||
#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_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_1_EAX_FEATURES 0
|
||||
#define TCG_APM_FEATURES 0
|
||||
@ -6035,6 +6035,19 @@ static void x86_cpu_reset(DeviceState *dev)
|
||||
#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)
|
||||
{
|
||||
CPUX86State *cenv = &cpu->env;
|
||||
|
@ -169,6 +169,7 @@ typedef enum X86Seg {
|
||||
#define HF_MPX_EN_SHIFT 25 /* MPX Enabled (CR4+XCR0+BNDCFGx) */
|
||||
#define HF_MPX_IU_SHIFT 26 /* BND registers in-use */
|
||||
#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_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_IU_MASK (1 << HF_MPX_IU_SHIFT)
|
||||
#define HF_UMIP_MASK (1 << HF_UMIP_SHIFT)
|
||||
#define HF_AVX_EN_MASK (1 << HF_AVX_EN_SHIFT)
|
||||
|
||||
/* hflags2 */
|
||||
|
||||
@ -1233,18 +1235,34 @@ typedef struct SegmentCache {
|
||||
uint32_t flags;
|
||||
} SegmentCache;
|
||||
|
||||
#define MMREG_UNION(n, bits) \
|
||||
union n { \
|
||||
uint8_t _b_##n[(bits)/8]; \
|
||||
uint16_t _w_##n[(bits)/16]; \
|
||||
uint32_t _l_##n[(bits)/32]; \
|
||||
uint64_t _q_##n[(bits)/64]; \
|
||||
float32 _s_##n[(bits)/32]; \
|
||||
float64 _d_##n[(bits)/64]; \
|
||||
}
|
||||
typedef union MMXReg {
|
||||
uint8_t _b_MMXReg[64 / 8];
|
||||
uint16_t _w_MMXReg[64 / 16];
|
||||
uint32_t _l_MMXReg[64 / 32];
|
||||
uint64_t _q_MMXReg[64 / 64];
|
||||
float32 _s_MMXReg[64 / 32];
|
||||
float64 _d_MMXReg[64 / 64];
|
||||
} MMXReg;
|
||||
|
||||
typedef MMREG_UNION(ZMMReg, 512) ZMMReg;
|
||||
typedef MMREG_UNION(MMXReg, 64) MMXReg;
|
||||
typedef union XMMReg {
|
||||
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 {
|
||||
uint64_t lb;
|
||||
@ -1267,6 +1285,13 @@ typedef struct BNDCSReg {
|
||||
#define ZMM_S(n) _s_ZMMReg[15 - (n)]
|
||||
#define ZMM_Q(n) _q_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_W(n) _w_MMXReg[3 - (n)]
|
||||
@ -1279,6 +1304,13 @@ typedef struct BNDCSReg {
|
||||
#define ZMM_S(n) _s_ZMMReg[n]
|
||||
#define ZMM_Q(n) _q_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_W(n) _w_MMXReg[n]
|
||||
@ -1556,8 +1588,8 @@ typedef struct CPUArchState {
|
||||
float_status mmx_status; /* for 3DNow! float ops */
|
||||
float_status sse_status;
|
||||
uint32_t mxcsr;
|
||||
ZMMReg xmm_regs[CPU_NB_REGS == 8 ? 8 : 32];
|
||||
ZMMReg xmm_t0;
|
||||
ZMMReg xmm_regs[CPU_NB_REGS == 8 ? 8 : 32] QEMU_ALIGNED(16);
|
||||
ZMMReg xmm_t0 QEMU_ALIGNED(16);
|
||||
MMXReg mmx_t0;
|
||||
|
||||
uint64_t opmask_regs[NB_OPMASK_REGS];
|
||||
@ -2082,6 +2114,8 @@ typedef struct PropValue {
|
||||
} PropValue;
|
||||
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);
|
||||
|
||||
/* cpu.c other functions (cpuid) */
|
||||
@ -2094,6 +2128,7 @@ void host_cpuid(uint32_t function, uint32_t count,
|
||||
|
||||
/* helper.c */
|
||||
void x86_cpu_set_a20(X86CPU *cpu, int a20_state);
|
||||
void cpu_sync_avx_hflag(CPUX86State *env);
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
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_USER_IDX 1
|
||||
#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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type,
|
||||
int *prot);
|
||||
#if defined(TARGET_X86_64) && \
|
||||
defined(CONFIG_USER_ONLY) && \
|
||||
defined(CONFIG_LINUX)
|
||||
|
@ -29,6 +29,17 @@
|
||||
#endif
|
||||
#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)
|
||||
{
|
||||
uint32_t hflags = env->hflags;
|
||||
@ -209,6 +220,7 @@ void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
|
||||
env->hflags = hflags;
|
||||
|
||||
cpu_sync_bndcs_hflags(env);
|
||||
cpu_sync_avx_hflag(env);
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
|
@ -212,12 +212,13 @@ DEF_HELPER_2(ldmxcsr, void, env, i32)
|
||||
DEF_HELPER_1(update_mxcsr, void, env)
|
||||
DEF_HELPER_1(enter_mmx, void, env)
|
||||
DEF_HELPER_1(emms, void, env)
|
||||
DEF_HELPER_3(movq, void, env, ptr, ptr)
|
||||
|
||||
#define SHIFT 0
|
||||
#include "ops_sse_header.h"
|
||||
#define SHIFT 1
|
||||
#include "ops_sse_header.h"
|
||||
#define SHIFT 2
|
||||
#include "ops_sse_header.h"
|
||||
|
||||
DEF_HELPER_3(rclb, tl, env, tl, tl)
|
||||
DEF_HELPER_3(rclw, tl, env, tl, tl)
|
||||
|
@ -23,6 +23,10 @@ int hyperv_x86_synic_add(X86CPU *cpu)
|
||||
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)
|
||||
{
|
||||
hyperv_synic_reset(CPU(cpu));
|
||||
|
@ -2203,14 +2203,6 @@ void kvm_arch_reset_vcpu(X86CPU *cpu)
|
||||
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 */
|
||||
env->poll_control_msr = 1;
|
||||
|
||||
@ -2219,6 +2211,24 @@ void kvm_arch_reset_vcpu(X86CPU *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)
|
||||
{
|
||||
CPUX86State *env = &cpu->env;
|
||||
|
@ -38,6 +38,7 @@ bool kvm_has_adjust_clock_stable(void);
|
||||
bool kvm_has_exception_payload(void);
|
||||
void kvm_synchronize_all_tsc(void);
|
||||
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_put_apicbase(X86CPU *cpu, uint64_t value);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -21,7 +21,11 @@
|
||||
#define SUFFIX _mmx
|
||||
#else
|
||||
#define Reg ZMMReg
|
||||
#if SHIFT == 1
|
||||
#define SUFFIX _xmm
|
||||
#else
|
||||
#define SUFFIX _ymm
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define dh_alias_Reg ptr
|
||||
@ -34,74 +38,34 @@
|
||||
#define dh_typecode_ZMMReg dh_typecode_ptr
|
||||
#define dh_typecode_MMXReg dh_typecode_ptr
|
||||
|
||||
DEF_HELPER_3(glue(psrlw, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(psraw, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(psllw, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(psrld, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(psrad, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(pslld, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(psrlq, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(psllq, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_4(glue(psrlw, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(psraw, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(psllw, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(psrld, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(psrad, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(pslld, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(psrlq, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(psllq, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
|
||||
#if SHIFT == 1
|
||||
DEF_HELPER_3(glue(psrldq, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(pslldq, SUFFIX), void, env, Reg, Reg)
|
||||
#if SHIFT >= 1
|
||||
DEF_HELPER_4(glue(psrldq, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(pslldq, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
#endif
|
||||
|
||||
#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)\
|
||||
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)\
|
||||
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)\
|
||||
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
|
||||
SSE_HELPER_W(pmulhrw, FMULHRW)
|
||||
DEF_HELPER_3(glue(pmulhrw, SUFFIX), void, env, Reg, Reg)
|
||||
#endif
|
||||
SSE_HELPER_W(pmulhuw, FMULHUW)
|
||||
SSE_HELPER_W(pmulhw, FMULHW)
|
||||
@ -109,51 +73,74 @@ SSE_HELPER_W(pmulhw, FMULHW)
|
||||
SSE_HELPER_B(pavgb, FAVG)
|
||||
SSE_HELPER_W(pavgw, FAVG)
|
||||
|
||||
DEF_HELPER_3(glue(pmuludq, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(pmaddwd, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_4(glue(pmuludq, SUFFIX), void, env, Reg, 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_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
|
||||
|
||||
#if SHIFT == 0
|
||||
DEF_HELPER_3(glue(pshufw, SUFFIX), void, Reg, Reg, int)
|
||||
#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(pshuflw, SUFFIX), void, Reg, Reg, int)
|
||||
DEF_HELPER_3(glue(pshufhw, SUFFIX), void, Reg, Reg, int)
|
||||
#endif
|
||||
|
||||
#if SHIFT == 1
|
||||
#if SHIFT >= 1
|
||||
/* FPU ops */
|
||||
/* XXX: not accurate */
|
||||
|
||||
#define SSE_HELPER_S(name, F) \
|
||||
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(name ## sd, void, env, Reg, Reg)
|
||||
#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)
|
||||
|
||||
SSE_HELPER_S(add, FPU_ADD)
|
||||
SSE_HELPER_S(sub, FPU_SUB)
|
||||
SSE_HELPER_S(mul, FPU_MUL)
|
||||
SSE_HELPER_S(div, FPU_DIV)
|
||||
SSE_HELPER_S(min, FPU_MIN)
|
||||
SSE_HELPER_S(max, FPU_MAX)
|
||||
SSE_HELPER_S(sqrt, FPU_SQRT)
|
||||
#define SSE_HELPER_P3(name, ...) \
|
||||
DEF_HELPER_3(glue(name ## ps, SUFFIX), void, env, Reg, Reg) \
|
||||
DEF_HELPER_3(glue(name ## pd, SUFFIX), void, env, Reg, Reg)
|
||||
|
||||
#if SHIFT == 1
|
||||
#define SSE_HELPER_S4(name) \
|
||||
SSE_HELPER_P4(name) \
|
||||
DEF_HELPER_4(name ## ss, void, env, Reg, Reg, Reg) \
|
||||
DEF_HELPER_4(name ## sd, void, env, Reg, Reg, Reg)
|
||||
#define SSE_HELPER_S3(name) \
|
||||
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(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(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(cvtpi2pd, void, env, ZMMReg, MMXReg)
|
||||
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)
|
||||
#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(cvtpd2pi, void, env, MMXReg, 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)
|
||||
#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(cvttpd2pi, void, env, MMXReg, 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(cvttsd2sq, s64, env, ZMMReg)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
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(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_4(extrq_i, void, env, ZMMReg, int, int)
|
||||
DEF_HELPER_3(insertq_r, void, env, ZMMReg, ZMMReg)
|
||||
DEF_HELPER_5(insertq_i, void, env, ZMMReg, ZMMReg, int, int)
|
||||
DEF_HELPER_3(glue(haddps, SUFFIX), void, env, ZMMReg, ZMMReg)
|
||||
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)
|
||||
#endif
|
||||
|
||||
#define SSE_HELPER_CMP(name, F, C) \
|
||||
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(name ## sd, void, env, Reg, Reg)
|
||||
SSE_HELPER_P4(hadd)
|
||||
SSE_HELPER_P4(hsub)
|
||||
SSE_HELPER_P4(addsub)
|
||||
|
||||
#define SSE_HELPER_CMP(name, F, C) SSE_HELPER_S4(name)
|
||||
|
||||
SSE_HELPER_CMP(cmpeq, FPU_CMPQ, FPU_EQ)
|
||||
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(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(comiss, void, env, Reg, Reg)
|
||||
DEF_HELPER_3(ucomisd, 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(movmskpd, SUFFIX), i32, env, Reg)
|
||||
#endif
|
||||
|
||||
DEF_HELPER_2(glue(pmovmskb, SUFFIX), i32, env, Reg)
|
||||
DEF_HELPER_3(glue(packsswb, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(packuswb, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(packssdw, SUFFIX), void, env, Reg, Reg)
|
||||
#define UNPCK_OP(base_name, base) \
|
||||
DEF_HELPER_3(glue(punpck ## base_name ## bw, SUFFIX), void, env, Reg, Reg) \
|
||||
DEF_HELPER_3(glue(punpck ## base_name ## wd, SUFFIX), void, env, Reg, Reg) \
|
||||
DEF_HELPER_3(glue(punpck ## base_name ## dq, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_4(glue(packsswb, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(packuswb, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(packssdw, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
#define UNPCK_OP(name, base) \
|
||||
DEF_HELPER_4(glue(punpck ## name ## bw, SUFFIX), void, env, Reg, Reg, Reg) \
|
||||
DEF_HELPER_4(glue(punpck ## name ## wd, SUFFIX), void, env, Reg, Reg, Reg) \
|
||||
DEF_HELPER_4(glue(punpck ## name ## dq, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
|
||||
UNPCK_OP(l, 0)
|
||||
UNPCK_OP(h, 1)
|
||||
|
||||
#if SHIFT == 1
|
||||
DEF_HELPER_3(glue(punpcklqdq, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(punpckhqdq, SUFFIX), void, env, Reg, Reg)
|
||||
#if SHIFT >= 1
|
||||
DEF_HELPER_4(glue(punpcklqdq, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(punpckhqdq, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
#endif
|
||||
|
||||
/* 3DNow! float ops */
|
||||
@ -265,28 +275,25 @@ DEF_HELPER_3(pswapd, void, env, MMXReg, MMXReg)
|
||||
#endif
|
||||
|
||||
/* SSSE3 op helpers */
|
||||
DEF_HELPER_3(glue(phaddw, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(phaddd, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(phaddsw, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(phsubw, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(phsubd, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(phsubsw, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(pabsb, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(pabsw, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(pabsd, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(pmaddubsw, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(pmulhrsw, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(pshufb, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(psignb, SUFFIX), void, env, Reg, Reg)
|
||||
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)
|
||||
DEF_HELPER_4(glue(phaddw, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(phaddd, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(phaddsw, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(phsubw, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(phsubd, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(phsubsw, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(pmaddubsw, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(pmulhrsw, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(pshufb, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(psignb, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(psignw, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(psignd, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_5(glue(palignr, SUFFIX), void, env, Reg, Reg, Reg, i32)
|
||||
|
||||
/* SSE4.1 op helpers */
|
||||
#if SHIFT == 1
|
||||
DEF_HELPER_3(glue(pblendvb, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(blendvps, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(blendvpd, SUFFIX), void, env, Reg, Reg)
|
||||
#if SHIFT >= 1
|
||||
DEF_HELPER_5(glue(pblendvb, SUFFIX), void, env, Reg, Reg, Reg, Reg)
|
||||
DEF_HELPER_5(glue(blendvps, SUFFIX), void, env, Reg, Reg, 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(pmovsxbw, 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(pmovzxwq, 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(pcmpeqq, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(packusdw, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(pminsb, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(pminsd, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(pminuw, SUFFIX), void, env, Reg, Reg)
|
||||
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(pmovsldup, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(pmovshdup, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_3(glue(pmovdldup, SUFFIX), void, env, Reg, Reg)
|
||||
DEF_HELPER_4(glue(pmuldq, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
DEF_HELPER_4(glue(packusdw, SUFFIX), void, env, Reg, Reg, Reg)
|
||||
#if SHIFT == 1
|
||||
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(roundpd, SUFFIX), void, env, Reg, Reg, i32)
|
||||
DEF_HELPER_4(glue(roundss, SUFFIX), void, env, Reg, Reg, i32)
|
||||
DEF_HELPER_4(glue(roundsd, SUFFIX), void, env, Reg, Reg, i32)
|
||||
DEF_HELPER_4(glue(blendps, SUFFIX), void, env, Reg, Reg, i32)
|
||||
DEF_HELPER_4(glue(blendpd, SUFFIX), void, env, Reg, Reg, i32)
|
||||
DEF_HELPER_4(glue(pblendw, SUFFIX), void, env, Reg, Reg, i32)
|
||||
DEF_HELPER_4(glue(dpps, SUFFIX), void, env, Reg, Reg, i32)
|
||||
DEF_HELPER_4(glue(dppd, SUFFIX), void, env, Reg, Reg, i32)
|
||||
DEF_HELPER_4(glue(mpsadbw, SUFFIX), void, env, Reg, Reg, i32)
|
||||
#if SHIFT == 1
|
||||
DEF_HELPER_5(roundss_xmm, void, env, Reg, Reg, Reg, i32)
|
||||
DEF_HELPER_5(roundsd_xmm, void, env, Reg, Reg, Reg, i32)
|
||||
#endif
|
||||
DEF_HELPER_5(glue(blendps, SUFFIX), void, env, Reg, Reg, Reg, i32)
|
||||
DEF_HELPER_5(glue(blendpd, SUFFIX), void, env, Reg, Reg, Reg, i32)
|
||||
DEF_HELPER_5(glue(pblendw, SUFFIX), void, env, Reg, 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
|
||||
|
||||
/* SSE4.2 op helpers */
|
||||
#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(pcmpestrm, 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
|
||||
|
||||
/* 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
|
||||
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_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
|
||||
|
||||
#undef SHIFT
|
||||
@ -354,6 +390,9 @@ DEF_HELPER_4(glue(pclmulqdq, SUFFIX), void, env, Reg, Reg, i32)
|
||||
#undef SSE_HELPER_W
|
||||
#undef SSE_HELPER_L
|
||||
#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 UNPCK_OP
|
||||
|
1795
target/i386/tcg/decode-new.c.inc
Normal file
1795
target/i386/tcg/decode-new.c.inc
Normal file
File diff suppressed because it is too large
Load Diff
249
target/i386/tcg/decode-new.h
Normal file
249
target/i386/tcg/decode-new.h
Normal 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
2234
target/i386/tcg/emit.c.inc
Normal file
File diff suppressed because it is too large
Load Diff
@ -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)
|
||||
{
|
||||
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) {
|
||||
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) {
|
||||
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)
|
||||
{
|
||||
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) {
|
||||
do_xrstor_sse(env, ptr, ra);
|
||||
} else {
|
||||
/* ??? When AVX is implemented, we may have to be more
|
||||
selective in the clearing. */
|
||||
memset(env->xmm_regs, 0, sizeof(env->xmm_regs));
|
||||
do_clear_sse(env);
|
||||
}
|
||||
}
|
||||
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) {
|
||||
@ -2955,6 +3027,7 @@ void helper_xsetbv(CPUX86State *env, uint32_t ecx, uint64_t mask)
|
||||
|
||||
env->xcr0 = mask;
|
||||
cpu_sync_bndcs_hflags(env);
|
||||
cpu_sync_avx_hflag(env);
|
||||
return;
|
||||
|
||||
do_gpf:
|
||||
@ -3053,14 +3126,11 @@ void helper_emms(CPUX86State *env)
|
||||
*(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
|
||||
#include "ops_sse.h"
|
||||
|
||||
#define SHIFT 1
|
||||
#include "ops_sse.h"
|
||||
|
||||
#define SHIFT 2
|
||||
#include "ops_sse.h"
|
||||
|
@ -22,150 +22,274 @@
|
||||
#include "exec/exec-all.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,
|
||||
int *prot);
|
||||
typedef struct TranslateResult {
|
||||
hwaddr paddr;
|
||||
int prot;
|
||||
int page_size;
|
||||
} TranslateResult;
|
||||
|
||||
#define GET_HPHYS(cs, gpa, access_type, prot) \
|
||||
(get_hphys_func ? get_hphys_func(cs, gpa, access_type, prot) : gpa)
|
||||
typedef enum TranslateFaultStage2 {
|
||||
S2_NONE,
|
||||
S2_GPA,
|
||||
S2_GPT,
|
||||
} TranslateFaultStage2;
|
||||
|
||||
static int mmu_translate(CPUState *cs, hwaddr addr, MMUTranslateFunc get_hphys_func,
|
||||
uint64_t cr3, int is_write1, int mmu_idx, int pg_mode,
|
||||
hwaddr *xlat, int *page_size, int *prot)
|
||||
typedef struct TranslateFault {
|
||||
int exception_index;
|
||||
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);
|
||||
CPUX86State *env = &cpu->env;
|
||||
uint64_t ptep, pte;
|
||||
int32_t a20_mask;
|
||||
target_ulong pde_addr, pte_addr;
|
||||
int error_code = 0;
|
||||
int is_dirty, is_write, is_user;
|
||||
uint64_t rsvd_mask = PG_ADDRESS_MASK & ~MAKE_64BIT_MASK(0, cpu->phys_bits);
|
||||
uint32_t page_offset;
|
||||
CPUTLBEntryFull *full;
|
||||
int flags;
|
||||
|
||||
inout->gaddr = addr;
|
||||
flags = probe_access_full(inout->env, addr, MMU_DATA_STORE,
|
||||
inout->ptw_idx, true, &inout->haddr, &full, 0);
|
||||
|
||||
if (unlikely(flags & TLB_INVALID_MASK)) {
|
||||
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;
|
||||
int page_size;
|
||||
|
||||
is_user = (mmu_idx == MMU_USER_IDX);
|
||||
is_write = is_write1 & 1;
|
||||
a20_mask = x86_get_a20_mask(env);
|
||||
|
||||
restart_all:
|
||||
rsvd_mask = ~MAKE_64BIT_MASK(0, env_archcpu(env)->phys_bits);
|
||||
rsvd_mask &= PG_ADDRESS_MASK;
|
||||
if (!(pg_mode & PG_MODE_NXE)) {
|
||||
rsvd_mask |= PG_NX_MASK;
|
||||
}
|
||||
|
||||
if (pg_mode & PG_MODE_PAE) {
|
||||
uint64_t pde, pdpe;
|
||||
target_ulong pdpe_addr;
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
if (pg_mode & PG_MODE_LMA) {
|
||||
bool la57 = pg_mode & PG_MODE_LA57;
|
||||
uint64_t pml5e_addr, pml5e;
|
||||
uint64_t pml4e_addr, pml4e;
|
||||
|
||||
if (la57) {
|
||||
pml5e_addr = ((cr3 & ~0xfff) +
|
||||
(((addr >> 48) & 0x1ff) << 3)) & a20_mask;
|
||||
pml5e_addr = GET_HPHYS(cs, pml5e_addr, MMU_DATA_STORE, NULL);
|
||||
pml5e = x86_ldq_phys(cs, pml5e_addr);
|
||||
if (!(pml5e & PG_PRESENT_MASK)) {
|
||||
if (pg_mode & PG_MODE_LA57) {
|
||||
/*
|
||||
* Page table level 5
|
||||
*/
|
||||
pte_addr = ((in->cr3 & ~0xfff) +
|
||||
(((addr >> 48) & 0x1ff) << 3)) & a20_mask;
|
||||
if (!ptw_translate(&pte_trans, pte_addr)) {
|
||||
return false;
|
||||
}
|
||||
restart_5:
|
||||
pte = ptw_ldq(&pte_trans);
|
||||
if (!(pte & PG_PRESENT_MASK)) {
|
||||
goto do_fault;
|
||||
}
|
||||
if (pml5e & (rsvd_mask | PG_PSE_MASK)) {
|
||||
if (pte & (rsvd_mask | PG_PSE_MASK)) {
|
||||
goto do_fault_rsvd;
|
||||
}
|
||||
if (!(pml5e & PG_ACCESSED_MASK)) {
|
||||
pml5e |= PG_ACCESSED_MASK;
|
||||
x86_stl_phys_notdirty(cs, pml5e_addr, pml5e);
|
||||
if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) {
|
||||
goto restart_5;
|
||||
}
|
||||
ptep = pml5e ^ PG_NX_MASK;
|
||||
ptep = pte ^ PG_NX_MASK;
|
||||
} else {
|
||||
pml5e = cr3;
|
||||
pte = in->cr3;
|
||||
ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
|
||||
}
|
||||
|
||||
pml4e_addr = ((pml5e & PG_ADDRESS_MASK) +
|
||||
(((addr >> 39) & 0x1ff) << 3)) & a20_mask;
|
||||
pml4e_addr = GET_HPHYS(cs, pml4e_addr, MMU_DATA_STORE, NULL);
|
||||
pml4e = x86_ldq_phys(cs, pml4e_addr);
|
||||
if (!(pml4e & PG_PRESENT_MASK)) {
|
||||
/*
|
||||
* Page table level 4
|
||||
*/
|
||||
pte_addr = ((pte & PG_ADDRESS_MASK) +
|
||||
(((addr >> 39) & 0x1ff) << 3)) & a20_mask;
|
||||
if (!ptw_translate(&pte_trans, pte_addr)) {
|
||||
return false;
|
||||
}
|
||||
restart_4:
|
||||
pte = ptw_ldq(&pte_trans);
|
||||
if (!(pte & PG_PRESENT_MASK)) {
|
||||
goto do_fault;
|
||||
}
|
||||
if (pml4e & (rsvd_mask | PG_PSE_MASK)) {
|
||||
if (pte & (rsvd_mask | PG_PSE_MASK)) {
|
||||
goto do_fault_rsvd;
|
||||
}
|
||||
if (!(pml4e & PG_ACCESSED_MASK)) {
|
||||
pml4e |= PG_ACCESSED_MASK;
|
||||
x86_stl_phys_notdirty(cs, pml4e_addr, pml4e);
|
||||
if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) {
|
||||
goto restart_4;
|
||||
}
|
||||
ptep &= pml4e ^ 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);
|
||||
pdpe = x86_ldq_phys(cs, pdpe_addr);
|
||||
if (!(pdpe & PG_PRESENT_MASK)) {
|
||||
ptep &= pte ^ PG_NX_MASK;
|
||||
|
||||
/*
|
||||
* Page table level 3
|
||||
*/
|
||||
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;
|
||||
}
|
||||
if (pdpe & rsvd_mask) {
|
||||
if (pte & rsvd_mask) {
|
||||
goto do_fault_rsvd;
|
||||
}
|
||||
ptep &= pdpe ^ PG_NX_MASK;
|
||||
if (!(pdpe & PG_ACCESSED_MASK)) {
|
||||
pdpe |= PG_ACCESSED_MASK;
|
||||
x86_stl_phys_notdirty(cs, pdpe_addr, pdpe);
|
||||
if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) {
|
||||
goto restart_3_lma;
|
||||
}
|
||||
if (pdpe & PG_PSE_MASK) {
|
||||
ptep &= pte ^ PG_NX_MASK;
|
||||
if (pte & PG_PSE_MASK) {
|
||||
/* 1 GB page */
|
||||
*page_size = 1024 * 1024 * 1024;
|
||||
pte_addr = pdpe_addr;
|
||||
pte = pdpe;
|
||||
page_size = 1024 * 1024 * 1024;
|
||||
goto do_check_protect;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/* XXX: load them when cr3 is loaded ? */
|
||||
pdpe_addr = ((cr3 & ~0x1f) + ((addr >> 27) & 0x18)) &
|
||||
a20_mask;
|
||||
pdpe_addr = GET_HPHYS(cs, pdpe_addr, MMU_DATA_STORE, NULL);
|
||||
pdpe = x86_ldq_phys(cs, pdpe_addr);
|
||||
if (!(pdpe & PG_PRESENT_MASK)) {
|
||||
goto do_fault;
|
||||
/*
|
||||
* Page table level 3
|
||||
*/
|
||||
pte_addr = ((in->cr3 & ~0x1f) + ((addr >> 27) & 0x18)) & a20_mask;
|
||||
if (!ptw_translate(&pte_trans, pte_addr)) {
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) {
|
||||
goto restart_3_nolma;
|
||||
}
|
||||
ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
|
||||
}
|
||||
|
||||
pde_addr = ((pdpe & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3)) &
|
||||
a20_mask;
|
||||
pde_addr = GET_HPHYS(cs, pde_addr, MMU_DATA_STORE, NULL);
|
||||
pde = x86_ldq_phys(cs, pde_addr);
|
||||
if (!(pde & PG_PRESENT_MASK)) {
|
||||
/*
|
||||
* Page table level 2
|
||||
*/
|
||||
pte_addr = ((pte & PG_ADDRESS_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;
|
||||
}
|
||||
if (pde & rsvd_mask) {
|
||||
if (pte & rsvd_mask) {
|
||||
goto do_fault_rsvd;
|
||||
}
|
||||
ptep &= pde ^ PG_NX_MASK;
|
||||
if (pde & PG_PSE_MASK) {
|
||||
if (pte & PG_PSE_MASK) {
|
||||
/* 2 MB page */
|
||||
*page_size = 2048 * 1024;
|
||||
pte_addr = pde_addr;
|
||||
pte = pde;
|
||||
page_size = 2048 * 1024;
|
||||
ptep &= pte ^ PG_NX_MASK;
|
||||
goto do_check_protect;
|
||||
}
|
||||
/* 4 KB page */
|
||||
if (!(pde & PG_ACCESSED_MASK)) {
|
||||
pde |= PG_ACCESSED_MASK;
|
||||
x86_stl_phys_notdirty(cs, pde_addr, pde);
|
||||
if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) {
|
||||
goto restart_2_pae;
|
||||
}
|
||||
pte_addr = ((pde & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3)) &
|
||||
a20_mask;
|
||||
pte_addr = GET_HPHYS(cs, pte_addr, MMU_DATA_STORE, NULL);
|
||||
pte = x86_ldq_phys(cs, pte_addr);
|
||||
ptep &= pte ^ PG_NX_MASK;
|
||||
|
||||
/*
|
||||
* 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)) {
|
||||
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 */
|
||||
ptep &= pte ^ PG_NX_MASK;
|
||||
*page_size = 4096;
|
||||
page_size = 4096;
|
||||
} else {
|
||||
uint32_t pde;
|
||||
|
||||
/* page directory entry */
|
||||
pde_addr = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)) &
|
||||
a20_mask;
|
||||
pde_addr = GET_HPHYS(cs, pde_addr, MMU_DATA_STORE, NULL);
|
||||
pde = x86_ldl_phys(cs, pde_addr);
|
||||
if (!(pde & PG_PRESENT_MASK)) {
|
||||
/*
|
||||
* Page table level 2
|
||||
*/
|
||||
pte_addr = ((in->cr3 & ~0xfff) + ((addr >> 20) & 0xffc)) & a20_mask;
|
||||
if (!ptw_translate(&pte_trans, pte_addr)) {
|
||||
return false;
|
||||
}
|
||||
restart_2_nopae:
|
||||
pte = ptw_ldl(&pte_trans);
|
||||
if (!(pte & PG_PRESENT_MASK)) {
|
||||
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 ((pde & PG_PSE_MASK) && (pg_mode & PG_MODE_PSE)) {
|
||||
*page_size = 4096 * 1024;
|
||||
pte_addr = pde_addr;
|
||||
|
||||
/* Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved.
|
||||
if ((pte & PG_PSE_MASK) && (pg_mode & PG_MODE_PSE)) {
|
||||
page_size = 4096 * 1024;
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
pte = pde | ((pde & 0x1fe000LL) << (32 - 13));
|
||||
pte = (uint32_t)pte | ((pte & 0x1fe000LL) << (32 - 13));
|
||||
rsvd_mask = 0x200000;
|
||||
goto do_check_protect_pse36;
|
||||
}
|
||||
|
||||
if (!(pde & PG_ACCESSED_MASK)) {
|
||||
pde |= PG_ACCESSED_MASK;
|
||||
x86_stl_phys_notdirty(cs, pde_addr, pde);
|
||||
if (!ptw_setl(&pte_trans, pte, PG_ACCESSED_MASK)) {
|
||||
goto restart_2_nopae;
|
||||
}
|
||||
|
||||
/* page directory entry */
|
||||
pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) &
|
||||
a20_mask;
|
||||
pte_addr = GET_HPHYS(cs, pte_addr, MMU_DATA_STORE, NULL);
|
||||
pte = x86_ldl_phys(cs, pte_addr);
|
||||
/*
|
||||
* Page table level 1
|
||||
*/
|
||||
pte_addr = ((pte & ~0xfffu) + ((addr >> 10) & 0xffc)) & a20_mask;
|
||||
if (!ptw_translate(&pte_trans, pte_addr)) {
|
||||
return false;
|
||||
}
|
||||
pte = ptw_ldl(&pte_trans);
|
||||
if (!(pte & PG_PRESENT_MASK)) {
|
||||
goto do_fault;
|
||||
}
|
||||
/* combine pde and pte user and rw protections */
|
||||
ptep &= pte | PG_NX_MASK;
|
||||
*page_size = 4096;
|
||||
page_size = 4096;
|
||||
rsvd_mask = 0;
|
||||
}
|
||||
|
||||
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:
|
||||
if (pte & rsvd_mask) {
|
||||
goto do_fault_rsvd;
|
||||
@ -233,17 +359,17 @@ do_check_protect_pse36:
|
||||
goto do_fault_protect;
|
||||
}
|
||||
|
||||
*prot = 0;
|
||||
if (mmu_idx != MMU_KSMAP_IDX || !(ptep & PG_USER_MASK)) {
|
||||
*prot |= PAGE_READ;
|
||||
int prot = 0;
|
||||
if (in->mmu_idx != MMU_KSMAP_IDX || !(ptep & PG_USER_MASK)) {
|
||||
prot |= PAGE_READ;
|
||||
if ((ptep & PG_RW_MASK) || !(is_user || (pg_mode & PG_MODE_WP))) {
|
||||
*prot |= PAGE_WRITE;
|
||||
prot |= PAGE_WRITE;
|
||||
}
|
||||
}
|
||||
if (!(ptep & PG_NX_MASK) &&
|
||||
(mmu_idx == MMU_USER_IDX ||
|
||||
(is_user ||
|
||||
!((pg_mode & PG_MODE_SMEP) && (ptep & PG_USER_MASK)))) {
|
||||
*prot |= PAGE_EXEC;
|
||||
prot |= PAGE_EXEC;
|
||||
}
|
||||
|
||||
if (ptep & PG_USER_MASK) {
|
||||
@ -262,182 +388,246 @@ do_check_protect_pse36:
|
||||
} else if (pkr_wd && (is_user || (pg_mode & PG_MODE_WP))) {
|
||||
pkr_prot &= ~PAGE_WRITE;
|
||||
}
|
||||
|
||||
*prot &= pkr_prot;
|
||||
if ((pkr_prot & (1 << is_write1)) == 0) {
|
||||
assert(is_write1 != 2);
|
||||
error_code |= PG_ERROR_PK_MASK;
|
||||
goto do_fault_protect;
|
||||
if ((pkr_prot & (1 << access_type)) == 0) {
|
||||
goto do_fault_pk_protect;
|
||||
}
|
||||
prot &= pkr_prot;
|
||||
}
|
||||
|
||||
if ((*prot & (1 << is_write1)) == 0) {
|
||||
if ((prot & (1 << access_type)) == 0) {
|
||||
goto do_fault_protect;
|
||||
}
|
||||
|
||||
/* yes, it can! */
|
||||
is_dirty = is_write && !(pte & PG_DIRTY_MASK);
|
||||
if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
|
||||
pte |= PG_ACCESSED_MASK;
|
||||
if (is_dirty) {
|
||||
pte |= PG_DIRTY_MASK;
|
||||
{
|
||||
uint32_t set = PG_ACCESSED_MASK;
|
||||
if (access_type == MMU_DATA_STORE) {
|
||||
set |= PG_DIRTY_MASK;
|
||||
} else if (!(pte & PG_DIRTY_MASK)) {
|
||||
/*
|
||||
* Only set write access if already dirty...
|
||||
* otherwise wait for dirty access.
|
||||
*/
|
||||
prot &= ~PAGE_WRITE;
|
||||
}
|
||||
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;
|
||||
}
|
||||
x86_stl_phys_notdirty(cs, pte_addr, pte);
|
||||
}
|
||||
|
||||
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 */
|
||||
pte &= PG_ADDRESS_MASK & ~(*page_size - 1);
|
||||
page_offset = addr & (*page_size - 1);
|
||||
*xlat = GET_HPHYS(cs, pte + page_offset, is_write1, prot);
|
||||
return PG_ERROR_OK;
|
||||
paddr = (pte & a20_mask & PG_ADDRESS_MASK & ~(page_size - 1))
|
||||
| (addr & (page_size - 1));
|
||||
|
||||
if (in->ptw_idx == MMU_NESTED_IDX) {
|
||||
CPUTLBEntryFull *full;
|
||||
int flags, nested_page_size;
|
||||
|
||||
flags = probe_access_full(env, paddr, access_type,
|
||||
MMU_NESTED_IDX, true,
|
||||
&pte_trans.haddr, &full, 0);
|
||||
if (unlikely(flags & TLB_INVALID_MASK)) {
|
||||
err->exception_index = 0; /* unused */
|
||||
err->error_code = env->error_code;
|
||||
err->cr2 = paddr;
|
||||
err->stage2 = S2_GPA;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Merge stage1 & stage2 protection bits. */
|
||||
prot &= full->prot;
|
||||
|
||||
/* Re-verify resulting protection. */
|
||||
if ((prot & (1 << access_type)) == 0) {
|
||||
goto do_fault_protect;
|
||||
}
|
||||
|
||||
/* Merge stage1 & stage2 addresses to final physical address. */
|
||||
nested_page_size = 1 << full->lg_page_size;
|
||||
paddr = (full->phys_addr & ~(nested_page_size - 1))
|
||||
| (paddr & (nested_page_size - 1));
|
||||
|
||||
/*
|
||||
* Use the larger of stage1 & stage2 page sizes, so that
|
||||
* invalidation works.
|
||||
*/
|
||||
if (nested_page_size > page_size) {
|
||||
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;
|
||||
error_code = PG_ERROR_RSVD_MASK;
|
||||
goto do_fault_cont;
|
||||
do_fault_protect:
|
||||
error_code |= PG_ERROR_P_MASK;
|
||||
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 |= (is_write << PG_ERROR_W_BIT);
|
||||
if (is_user)
|
||||
error_code = 0;
|
||||
do_fault_cont:
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
hwaddr get_hphys(CPUState *cs, hwaddr gphys, MMUAccessType access_type,
|
||||
int *prot)
|
||||
static G_NORETURN void raise_stage2(CPUX86State *env, TranslateFault *err,
|
||||
uintptr_t retaddr)
|
||||
{
|
||||
CPUX86State *env = &X86_CPU(cs)->env;
|
||||
uint64_t exit_info_1;
|
||||
int page_size;
|
||||
int next_prot;
|
||||
hwaddr hphys;
|
||||
uint64_t exit_info_1 = err->error_code;
|
||||
|
||||
if (likely(!(env->hflags2 & HF2_NPT_MASK))) {
|
||||
return gphys;
|
||||
}
|
||||
|
||||
exit_info_1 = mmu_translate(cs, gphys, NULL, env->nested_cr3,
|
||||
access_type, MMU_USER_IDX, env->nested_pg_mode,
|
||||
&hphys, &page_size, &next_prot);
|
||||
if (exit_info_1 == PG_ERROR_OK) {
|
||||
if (prot) {
|
||||
*prot &= next_prot;
|
||||
}
|
||||
return hphys;
|
||||
}
|
||||
|
||||
x86_stq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
|
||||
gphys);
|
||||
if (prot) {
|
||||
exit_info_1 |= SVM_NPTEXIT_GPA;
|
||||
} else { /* page table access */
|
||||
switch (err->stage2) {
|
||||
case S2_GPT:
|
||||
exit_info_1 |= SVM_NPTEXIT_GPT;
|
||||
break;
|
||||
case S2_GPA:
|
||||
exit_info_1 |= SVM_NPTEXIT_GPA;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
cpu_vmexit(env, SVM_EXIT_NPF, exit_info_1, env->retaddr);
|
||||
|
||||
x86_stq_phys(env_cpu(env),
|
||||
env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2),
|
||||
err->cr2);
|
||||
cpu_vmexit(env, SVM_EXIT_NPF, exit_info_1, retaddr);
|
||||
}
|
||||
|
||||
/* return value:
|
||||
* -1 = cannot handle fault
|
||||
* 0 = nothing more to do
|
||||
* 1 = generate PF fault
|
||||
*/
|
||||
static int handle_mmu_fault(CPUState *cs, vaddr addr, int size,
|
||||
int is_write1, int mmu_idx)
|
||||
static bool get_physical_address(CPUX86State *env, vaddr addr,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
TranslateResult *out, TranslateFault *err)
|
||||
{
|
||||
X86CPU *cpu = X86_CPU(cs);
|
||||
CPUX86State *env = &cpu->env;
|
||||
int error_code = PG_ERROR_OK;
|
||||
int pg_mode, prot, page_size;
|
||||
int32_t a20_mask;
|
||||
hwaddr paddr;
|
||||
hwaddr vaddr;
|
||||
TranslateParams in;
|
||||
bool use_stage2 = env->hflags2 & HF2_NPT_MASK;
|
||||
|
||||
#if defined(DEBUG_MMU)
|
||||
printf("MMU fault: addr=%" VADDR_PRIx " w=%d mmu=%d eip=" TARGET_FMT_lx "\n",
|
||||
addr, is_write1, mmu_idx, env->eip);
|
||||
#endif
|
||||
in.addr = addr;
|
||||
in.access_type = access_type;
|
||||
|
||||
if (!(env->cr[0] & CR0_PG_MASK)) {
|
||||
a20_mask = x86_get_a20_mask(env);
|
||||
paddr = addr & a20_mask;
|
||||
#ifdef TARGET_X86_64
|
||||
if (!(env->hflags & HF_LMA_MASK)) {
|
||||
/* Without long mode we can only address 32bits in real mode */
|
||||
paddr = (uint32_t)paddr;
|
||||
}
|
||||
#endif
|
||||
prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
|
||||
page_size = 4096;
|
||||
} else {
|
||||
pg_mode = get_pg_mode(env);
|
||||
if (pg_mode & PG_MODE_LMA) {
|
||||
int32_t sext;
|
||||
switch (mmu_idx) {
|
||||
case MMU_PHYS_IDX:
|
||||
break;
|
||||
|
||||
/* 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;
|
||||
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;
|
||||
|
||||
error_code = mmu_translate(cs, addr, get_hphys, env->cr[3], is_write1,
|
||||
mmu_idx, pg_mode,
|
||||
&paddr, &page_size, &prot);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
/* Translation disabled. */
|
||||
out->paddr = addr & x86_get_a20_mask(env);
|
||||
#ifdef TARGET_X86_64
|
||||
if (!(env->hflags & HF_LMA_MASK)) {
|
||||
/* Without long mode we can only address 32bits in real mode */
|
||||
out->paddr = (uint32_t)out->paddr;
|
||||
}
|
||||
#endif
|
||||
out->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
|
||||
out->page_size = TARGET_PAGE_SIZE;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool x86_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
|
||||
MMUAccessType access_type, int mmu_idx,
|
||||
bool probe, uintptr_t retaddr)
|
||||
{
|
||||
X86CPU *cpu = X86_CPU(cs);
|
||||
CPUX86State *env = &cpu->env;
|
||||
CPUX86State *env = cs->env_ptr;
|
||||
TranslateResult out;
|
||||
TranslateFault err;
|
||||
|
||||
env->retaddr = retaddr;
|
||||
if (handle_mmu_fault(cs, addr, size, access_type, mmu_idx)) {
|
||||
/* FIXME: On error in get_hphys we have already jumped out. */
|
||||
g_assert(!probe);
|
||||
raise_exception_err_ra(env, cs->exception_index,
|
||||
env->error_code, retaddr);
|
||||
if (get_physical_address(env, addr, access_type, mmu_idx, &out, &err)) {
|
||||
/*
|
||||
* Even if 4MB pages, we map only one 4KB page in the cache to
|
||||
* avoid filling it too fast.
|
||||
*/
|
||||
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,
|
||||
|
@ -27,19 +27,19 @@
|
||||
|
||||
/* Secure Virtual Machine helpers */
|
||||
|
||||
static inline void svm_save_seg(CPUX86State *env, hwaddr addr,
|
||||
const SegmentCache *sc)
|
||||
static void svm_save_seg(CPUX86State *env, int mmu_idx, hwaddr addr,
|
||||
const SegmentCache *sc)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
|
||||
x86_stw_phys(cs, addr + offsetof(struct vmcb_seg, selector),
|
||||
sc->selector);
|
||||
x86_stq_phys(cs, addr + offsetof(struct vmcb_seg, base),
|
||||
sc->base);
|
||||
x86_stl_phys(cs, addr + offsetof(struct vmcb_seg, limit),
|
||||
sc->limit);
|
||||
x86_stw_phys(cs, addr + offsetof(struct vmcb_seg, attrib),
|
||||
((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00));
|
||||
cpu_stw_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, selector),
|
||||
sc->selector, mmu_idx, 0);
|
||||
cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, base),
|
||||
sc->base, mmu_idx, 0);
|
||||
cpu_stl_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, limit),
|
||||
sc->limit, mmu_idx, 0);
|
||||
cpu_stw_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, attrib),
|
||||
((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);
|
||||
}
|
||||
|
||||
static inline void svm_load_seg(CPUX86State *env, hwaddr addr,
|
||||
SegmentCache *sc)
|
||||
static void svm_load_seg(CPUX86State *env, int mmu_idx, hwaddr addr,
|
||||
SegmentCache *sc)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
unsigned int flags;
|
||||
|
||||
sc->selector = x86_lduw_phys(cs,
|
||||
addr + offsetof(struct vmcb_seg, selector));
|
||||
sc->base = x86_ldq_phys(cs, addr + offsetof(struct vmcb_seg, base));
|
||||
sc->limit = x86_ldl_phys(cs, addr + offsetof(struct vmcb_seg, limit));
|
||||
flags = x86_lduw_phys(cs, addr + offsetof(struct vmcb_seg, attrib));
|
||||
sc->selector =
|
||||
cpu_lduw_mmuidx_ra(env, addr + offsetof(struct vmcb_seg, selector),
|
||||
mmu_idx, 0);
|
||||
sc->base =
|
||||
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);
|
||||
|
||||
svm_canonicalization(env, &sc->base);
|
||||
}
|
||||
|
||||
static inline void svm_load_seg_cache(CPUX86State *env, hwaddr addr,
|
||||
int seg_reg)
|
||||
static void svm_load_seg_cache(CPUX86State *env, int mmu_idx,
|
||||
hwaddr addr, int seg_reg)
|
||||
{
|
||||
SegmentCache sc1, *sc = &sc1;
|
||||
SegmentCache sc;
|
||||
|
||||
svm_load_seg(env, addr, sc);
|
||||
cpu_x86_load_seg_cache(env, seg_reg, sc->selector,
|
||||
sc->base, sc->limit, sc->flags);
|
||||
svm_load_seg(env, mmu_idx, addr, &sc);
|
||||
cpu_x86_load_seg_cache(env, seg_reg, sc.selector,
|
||||
sc.base, sc.limit, sc.flags);
|
||||
}
|
||||
|
||||
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),
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
|
||||
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->nested_pg_mode = get_pg_mode(env) & PG_MODE_SVM_MASK;
|
||||
|
||||
tlb_flush_by_mmuidx(cs, 1 << MMU_NESTED_IDX);
|
||||
}
|
||||
|
||||
/* enable intercepts */
|
||||
@ -323,18 +336,18 @@ void helper_vmrun(CPUX86State *env, int aflag, int next_eip_addend)
|
||||
save.rflags)),
|
||||
~(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),
|
||||
R_ES);
|
||||
svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.cs),
|
||||
R_CS);
|
||||
svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ss),
|
||||
R_SS);
|
||||
svm_load_seg_cache(env, env->vm_vmcb + offsetof(struct vmcb, save.ds),
|
||||
R_DS);
|
||||
svm_load_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.idtr),
|
||||
&env->idt);
|
||||
svm_load_seg(env, env->vm_vmcb + offsetof(struct vmcb, save.gdtr),
|
||||
&env->gdt);
|
||||
svm_load_seg_cache(env, MMU_PHYS_IDX,
|
||||
env->vm_vmcb + offsetof(struct vmcb, save.es), R_ES);
|
||||
svm_load_seg_cache(env, MMU_PHYS_IDX,
|
||||
env->vm_vmcb + offsetof(struct vmcb, save.cs), R_CS);
|
||||
svm_load_seg_cache(env, MMU_PHYS_IDX,
|
||||
env->vm_vmcb + offsetof(struct vmcb, save.ss), R_SS);
|
||||
svm_load_seg_cache(env, MMU_PHYS_IDX,
|
||||
env->vm_vmcb + offsetof(struct vmcb, save.ds), R_DS);
|
||||
svm_load_seg(env, MMU_PHYS_IDX,
|
||||
env->vm_vmcb + offsetof(struct vmcb, save.idtr), &env->idt);
|
||||
svm_load_seg(env, MMU_PHYS_IDX,
|
||||
env->vm_vmcb + offsetof(struct vmcb, save.gdtr), &env->gdt);
|
||||
|
||||
env->eip = x86_ldq_phys(cs,
|
||||
env->vm_vmcb + offsetof(struct vmcb, save.rip));
|
||||
@ -449,9 +462,8 @@ void helper_vmmcall(CPUX86State *env)
|
||||
|
||||
void helper_vmload(CPUX86State *env, int aflag)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
int mmu_idx = MMU_PHYS_IDX;
|
||||
target_ulong addr;
|
||||
int prot;
|
||||
|
||||
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())) {
|
||||
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
|
||||
"\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_load_seg_cache(env, addr + offsetof(struct vmcb, save.fs), R_FS);
|
||||
svm_load_seg_cache(env, addr + offsetof(struct vmcb, save.gs), R_GS);
|
||||
svm_load_seg(env, addr + offsetof(struct vmcb, save.tr), &env->tr);
|
||||
svm_load_seg(env, addr + offsetof(struct vmcb, save.ldtr), &env->ldt);
|
||||
svm_load_seg_cache(env, mmu_idx,
|
||||
addr + offsetof(struct vmcb, save.fs), R_FS);
|
||||
svm_load_seg_cache(env, mmu_idx,
|
||||
addr + offsetof(struct vmcb, save.gs), R_GS);
|
||||
svm_load_seg(env, mmu_idx,
|
||||
addr + offsetof(struct vmcb, save.tr), &env->tr);
|
||||
svm_load_seg(env, mmu_idx,
|
||||
addr + offsetof(struct vmcb, save.ldtr), &env->ldt);
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
env->kernelgsbase = x86_ldq_phys(cs, addr + offsetof(struct vmcb,
|
||||
save.kernel_gs_base));
|
||||
env->lstar = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.lstar));
|
||||
env->cstar = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.cstar));
|
||||
env->fmask = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.sfmask));
|
||||
env->kernelgsbase =
|
||||
cpu_ldq_mmuidx_ra(env,
|
||||
addr + offsetof(struct vmcb, save.kernel_gs_base),
|
||||
mmu_idx, 0);
|
||||
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);
|
||||
#endif
|
||||
env->star = x86_ldq_phys(cs, addr + offsetof(struct vmcb, save.star));
|
||||
env->sysenter_cs = x86_ldq_phys(cs,
|
||||
addr + offsetof(struct vmcb, save.sysenter_cs));
|
||||
env->sysenter_esp = x86_ldq_phys(cs, addr + offsetof(struct vmcb,
|
||||
save.sysenter_esp));
|
||||
env->sysenter_eip = x86_ldq_phys(cs, addr + offsetof(struct vmcb,
|
||||
save.sysenter_eip));
|
||||
|
||||
env->star =
|
||||
cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.star),
|
||||
mmu_idx, 0);
|
||||
env->sysenter_cs =
|
||||
cpu_ldq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_cs),
|
||||
mmu_idx, 0);
|
||||
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)
|
||||
{
|
||||
CPUState *cs = env_cpu(env);
|
||||
int mmu_idx = MMU_PHYS_IDX;
|
||||
target_ulong addr;
|
||||
int prot;
|
||||
|
||||
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())) {
|
||||
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
|
||||
"\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),
|
||||
svm_save_seg(env, mmu_idx, addr + offsetof(struct vmcb, save.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]);
|
||||
svm_save_seg(env, addr + offsetof(struct vmcb, save.tr),
|
||||
svm_save_seg(env, mmu_idx, addr + offsetof(struct vmcb, save.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);
|
||||
|
||||
#ifdef TARGET_X86_64
|
||||
x86_stq_phys(cs, addr + offsetof(struct vmcb, save.kernel_gs_base),
|
||||
env->kernelgsbase);
|
||||
x86_stq_phys(cs, addr + offsetof(struct vmcb, save.lstar), env->lstar);
|
||||
x86_stq_phys(cs, addr + offsetof(struct vmcb, save.cstar), env->cstar);
|
||||
x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sfmask), env->fmask);
|
||||
cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.kernel_gs_base),
|
||||
env->kernelgsbase, mmu_idx, 0);
|
||||
cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.lstar),
|
||||
env->lstar, mmu_idx, 0);
|
||||
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
|
||||
x86_stq_phys(cs, addr + offsetof(struct vmcb, save.star), env->star);
|
||||
x86_stq_phys(cs,
|
||||
addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs);
|
||||
x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sysenter_esp),
|
||||
env->sysenter_esp);
|
||||
x86_stq_phys(cs, addr + offsetof(struct vmcb, save.sysenter_eip),
|
||||
env->sysenter_eip);
|
||||
cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.star),
|
||||
env->star, mmu_idx, 0);
|
||||
cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_cs),
|
||||
env->sysenter_cs, mmu_idx, 0);
|
||||
cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_esp),
|
||||
env->sysenter_esp, mmu_idx, 0);
|
||||
cpu_stq_mmuidx_ra(env, addr + offsetof(struct vmcb, save.sysenter_eip),
|
||||
env->sysenter_eip, mmu_idx, 0);
|
||||
}
|
||||
|
||||
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->hflags2 &= ~HF2_NPT_MASK;
|
||||
tlb_flush_by_mmuidx(cs, 1 << MMU_NESTED_IDX);
|
||||
|
||||
/* 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]);
|
||||
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]);
|
||||
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]);
|
||||
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]);
|
||||
|
||||
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 |
|
||||
VM_MASK));
|
||||
|
||||
svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.es),
|
||||
R_ES);
|
||||
svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.cs),
|
||||
R_CS);
|
||||
svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.ss),
|
||||
R_SS);
|
||||
svm_load_seg_cache(env, env->vm_hsave + offsetof(struct vmcb, save.ds),
|
||||
R_DS);
|
||||
svm_load_seg_cache(env, MMU_PHYS_IDX,
|
||||
env->vm_hsave + offsetof(struct vmcb, save.es), R_ES);
|
||||
svm_load_seg_cache(env, MMU_PHYS_IDX,
|
||||
env->vm_hsave + offsetof(struct vmcb, save.cs), R_CS);
|
||||
svm_load_seg_cache(env, MMU_PHYS_IDX,
|
||||
env->vm_hsave + offsetof(struct vmcb, save.ss), R_SS);
|
||||
svm_load_seg_cache(env, MMU_PHYS_IDX,
|
||||
env->vm_hsave + offsetof(struct vmcb, save.ds), R_DS);
|
||||
|
||||
env->eip = x86_ldq_phys(cs,
|
||||
env->vm_hsave + offsetof(struct vmcb, save.rip));
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -107,7 +107,7 @@ run-test-mmx: QEMU_OPTS += -cpu max
|
||||
run-plugin-test-mmx: QEMU_OPTS += -cpu max
|
||||
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-plugin-test-avx: QEMU_OPTS += -cpu max
|
||||
test-avx: test-avx.h
|
||||
|
@ -6,18 +6,18 @@
|
||||
typedef void (*testfn)(void);
|
||||
|
||||
typedef struct {
|
||||
uint64_t q0, q1;
|
||||
} __attribute__((aligned(16))) v2di;
|
||||
uint64_t q0, q1, q2, q3;
|
||||
} __attribute__((aligned(32))) v4di;
|
||||
|
||||
typedef struct {
|
||||
uint64_t mm[8];
|
||||
v2di xmm[16];
|
||||
v4di ymm[16];
|
||||
uint64_t r[16];
|
||||
uint64_t flags;
|
||||
uint32_t ff;
|
||||
uint64_t pad;
|
||||
v2di mem[4];
|
||||
v2di mem0[4];
|
||||
v4di mem[4];
|
||||
v4di mem0[4];
|
||||
} reg_state;
|
||||
|
||||
typedef struct {
|
||||
@ -31,20 +31,20 @@ reg_state initI;
|
||||
reg_state initF32;
|
||||
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",
|
||||
name, n, r->q1, r->q0);
|
||||
printf("%s%d = %016lx %016lx %016lx %016lx\n",
|
||||
name, n, r->q3, r->q2, r->q1, r->q0);
|
||||
if (ff == 64) {
|
||||
double v[2];
|
||||
double v[4];
|
||||
memcpy(v, r, sizeof(v));
|
||||
printf(" %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",
|
||||
printf(" %16g %16g %16g %16g\n",
|
||||
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;
|
||||
|
||||
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++) {
|
||||
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++) {
|
||||
if (memcmp(&a->xmm[i], &b->xmm[i], 16)) {
|
||||
dump_xmm("xmm", i, &b->xmm[i], a->ff);
|
||||
if (memcmp(&a->ymm[i], &b->ymm[i], 32)) {
|
||||
dump_ymm("ymm", i, &b->ymm[i], a->ff);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (memcmp(&a->mem0[i], &a->mem[i], 16)) {
|
||||
dump_xmm("mem", i, &a->mem[i], a->ff);
|
||||
if (memcmp(&a->mem0[i], &a->mem[i], 32)) {
|
||||
dump_ymm("mem", i, &a->mem[i], a->ff);
|
||||
}
|
||||
}
|
||||
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 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 STOREXMM(r, o) "movdqa " #o "[%1], " #r "\n\t"
|
||||
#define STOREYMM(r, o) "vmovdqa " #o "[%1], " #r "\n\t"
|
||||
#define MMREG(F) \
|
||||
F(mm0, 0x00) \
|
||||
F(mm1, 0x08) \
|
||||
@ -101,39 +101,39 @@ static void compare_state(const reg_state *a, const reg_state *b)
|
||||
F(mm5, 0x28) \
|
||||
F(mm6, 0x30) \
|
||||
F(mm7, 0x38)
|
||||
#define XMMREG(F) \
|
||||
F(xmm0, 0x040) \
|
||||
F(xmm1, 0x050) \
|
||||
F(xmm2, 0x060) \
|
||||
F(xmm3, 0x070) \
|
||||
F(xmm4, 0x080) \
|
||||
F(xmm5, 0x090) \
|
||||
F(xmm6, 0x0a0) \
|
||||
F(xmm7, 0x0b0) \
|
||||
F(xmm8, 0x0c0) \
|
||||
F(xmm9, 0x0d0) \
|
||||
F(xmm10, 0x0e0) \
|
||||
F(xmm11, 0x0f0) \
|
||||
F(xmm12, 0x100) \
|
||||
F(xmm13, 0x110) \
|
||||
F(xmm14, 0x120) \
|
||||
F(xmm15, 0x130)
|
||||
#define YMMREG(F) \
|
||||
F(ymm0, 0x040) \
|
||||
F(ymm1, 0x060) \
|
||||
F(ymm2, 0x080) \
|
||||
F(ymm3, 0x0a0) \
|
||||
F(ymm4, 0x0c0) \
|
||||
F(ymm5, 0x0e0) \
|
||||
F(ymm6, 0x100) \
|
||||
F(ymm7, 0x120) \
|
||||
F(ymm8, 0x140) \
|
||||
F(ymm9, 0x160) \
|
||||
F(ymm10, 0x180) \
|
||||
F(ymm11, 0x1a0) \
|
||||
F(ymm12, 0x1c0) \
|
||||
F(ymm13, 0x1e0) \
|
||||
F(ymm14, 0x200) \
|
||||
F(ymm15, 0x220)
|
||||
#define LOADREG(r, o) "mov " #r ", " #o "[rax]\n\t"
|
||||
#define STOREREG(r, o) "mov " #o "[rax], " #r "\n\t"
|
||||
#define REG(F) \
|
||||
F(rbx, 0x148) \
|
||||
F(rcx, 0x150) \
|
||||
F(rdx, 0x158) \
|
||||
F(rsi, 0x160) \
|
||||
F(rdi, 0x168) \
|
||||
F(r8, 0x180) \
|
||||
F(r9, 0x188) \
|
||||
F(r10, 0x190) \
|
||||
F(r11, 0x198) \
|
||||
F(r12, 0x1a0) \
|
||||
F(r13, 0x1a8) \
|
||||
F(r14, 0x1b0) \
|
||||
F(r15, 0x1b8) \
|
||||
F(rbx, 0x248) \
|
||||
F(rcx, 0x250) \
|
||||
F(rdx, 0x258) \
|
||||
F(rsi, 0x260) \
|
||||
F(rdi, 0x268) \
|
||||
F(r8, 0x280) \
|
||||
F(r9, 0x288) \
|
||||
F(r10, 0x290) \
|
||||
F(r11, 0x298) \
|
||||
F(r12, 0x2a0) \
|
||||
F(r13, 0x2a8) \
|
||||
F(r14, 0x2b0) \
|
||||
F(r15, 0x2b8) \
|
||||
|
||||
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);
|
||||
asm volatile(
|
||||
MMREG(LOADMM)
|
||||
XMMREG(LOADXMM)
|
||||
YMMREG(LOADYMM)
|
||||
"sub rsp, 128\n\t"
|
||||
"push rax\n\t"
|
||||
"push rbx\n\t"
|
||||
@ -156,26 +156,26 @@ static void run_test(const TestDef *t)
|
||||
"pop rbx\n\t"
|
||||
"shr 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"
|
||||
"or rbx, rcx\n\t"
|
||||
"push rbx\n\t"
|
||||
"popf\n\t"
|
||||
REG(LOADREG)
|
||||
"mov rax, 0x140[rax]\n\t"
|
||||
"mov rax, 0x240[rax]\n\t"
|
||||
"call [rsp]\n\t"
|
||||
"mov [rsp], rax\n\t"
|
||||
"mov rax, 8[rsp]\n\t"
|
||||
REG(STOREREG)
|
||||
"mov rbx, [rsp]\n\t"
|
||||
"mov 0x140[rax], rbx\n\t"
|
||||
"mov 0x240[rax], rbx\n\t"
|
||||
"mov rbx, 0\n\t"
|
||||
"mov 0x170[rax], rbx\n\t"
|
||||
"mov 0x178[rax], rbx\n\t"
|
||||
"mov 0x270[rax], rbx\n\t"
|
||||
"mov 0x278[rax], rbx\n\t"
|
||||
"pushf\n\t"
|
||||
"pop rbx\n\t"
|
||||
"and rbx, 0xff\n\t"
|
||||
"mov 0x1c0[rax], rbx\n\t"
|
||||
"mov 0x2c0[rax], rbx\n\t"
|
||||
"add rsp, 16\n\t"
|
||||
"pop rdx\n\t"
|
||||
"pop rcx\n\t"
|
||||
@ -183,15 +183,15 @@ static void run_test(const TestDef *t)
|
||||
"pop rax\n\t"
|
||||
"add rsp, 128\n\t"
|
||||
MMREG(STOREMM)
|
||||
XMMREG(STOREXMM)
|
||||
YMMREG(STOREYMM)
|
||||
: : "r"(init), "r"(&result), "r"(t->fn)
|
||||
: "memory", "cc",
|
||||
"rsi", "rdi",
|
||||
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
|
||||
"mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
|
||||
"xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5",
|
||||
"xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11",
|
||||
"xmm12", "xmm13", "xmm14", "xmm15"
|
||||
"ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5",
|
||||
"ymm6", "ymm7", "ymm8", "ymm9", "ymm10", "ymm11",
|
||||
"ymm12", "ymm13", "ymm14", "ymm15"
|
||||
);
|
||||
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};
|
||||
double val_f64[] = {2.0, -1.0, 4.8, 0.8, 3, -42.0, 5e6, 7.5};
|
||||
v2di val_i64[] = {
|
||||
{0x3d6b3b6a9e4118f2lu, 0x355ae76d2774d78clu},
|
||||
{0xd851c54a56bf1f29lu, 0x4a84d1d50bf4c4fflu},
|
||||
{0x5826475e2c5fd799lu, 0xfd32edc01243f5e9lu},
|
||||
v4di val_i64[] = {
|
||||
{0x3d6b3b6a9e4118f2lu, 0x355ae76d2774d78clu,
|
||||
0xac3ff76c4daa4b28lu, 0xe7fabd204cb54083lu},
|
||||
{0xd851c54a56bf1f29lu, 0x4a84d1d50bf4c4fflu,
|
||||
0x56621e553d52b56clu, 0xd0069553da8f584alu},
|
||||
{0x5826475e2c5fd799lu, 0xfd32edc01243f5e9lu,
|
||||
0x738ba2c66d3fe126lu, 0x5707219c6e6c26b4lu},
|
||||
};
|
||||
|
||||
v2di deadbeef = {0xa5a5a5a5deadbeefull, 0xa5a5a5a5deadbeefull};
|
||||
v2di indexq = {0x000000000000001full, 0x000000000000008full};
|
||||
v2di indexd = {0x00000002000000efull, 0xfffffff500000010ull};
|
||||
v4di deadbeef = {0xa5a5a5a5deadbeefull, 0xa5a5a5a5deadbeefull,
|
||||
0xa5a5a5a5deadbeefull, 0xa5a5a5a5deadbeefull};
|
||||
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;
|
||||
float v[4];
|
||||
float v[8];
|
||||
int i;
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (i = 0; i < 8; i++) {
|
||||
v[i] = val_f32[n++];
|
||||
if (n == ARRAY_LEN(val_f32)) {
|
||||
n = 0;
|
||||
@ -247,12 +255,12 @@ void init_f32reg(v2di *r)
|
||||
memcpy(r, v, sizeof(*r));
|
||||
}
|
||||
|
||||
void init_f64reg(v2di *r)
|
||||
void init_f64reg(v4di *r)
|
||||
{
|
||||
static int n;
|
||||
double v[2];
|
||||
double v[4];
|
||||
int i;
|
||||
for (i = 0; i < 2; i++) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
v[i] = val_f64[n++];
|
||||
if (n == ARRAY_LEN(val_f64)) {
|
||||
n = 0;
|
||||
@ -261,13 +269,15 @@ void init_f64reg(v2di *r)
|
||||
memcpy(r, v, sizeof(*r));
|
||||
}
|
||||
|
||||
void init_intreg(v2di *r)
|
||||
void init_intreg(v4di *r)
|
||||
{
|
||||
static uint64_t mask;
|
||||
static int n;
|
||||
|
||||
r->q0 = val_i64[n].q0 ^ mask;
|
||||
r->q1 = val_i64[n].q1 ^ mask;
|
||||
r->q2 = val_i64[n].q2 ^ mask;
|
||||
r->q3 = val_i64[n].q3 ^ mask;
|
||||
n++;
|
||||
if (n == ARRAY_LEN(val_i64)) {
|
||||
n = 0;
|
||||
@ -280,46 +290,53 @@ static void init_all(reg_state *s)
|
||||
int i;
|
||||
|
||||
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->flags = 2;
|
||||
for (i = 0; i < 8; i++) {
|
||||
s->xmm[i] = deadbeef;
|
||||
for (i = 0; i < 16; i++) {
|
||||
s->ymm[i] = deadbeef;
|
||||
}
|
||||
s->xmm[13] = indexd;
|
||||
s->xmm[14] = indexq;
|
||||
for (i = 0; i < 2; i++) {
|
||||
s->ymm[13] = indexd;
|
||||
s->ymm[14] = indexq;
|
||||
for (i = 0; i < 4; i++) {
|
||||
s->mem0[i] = deadbeef;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
init_all(&initI);
|
||||
init_intreg(&initI.xmm[10]);
|
||||
init_intreg(&initI.xmm[11]);
|
||||
init_intreg(&initI.xmm[12]);
|
||||
init_intreg(&initI.ymm[10]);
|
||||
init_intreg(&initI.ymm[11]);
|
||||
init_intreg(&initI.ymm[12]);
|
||||
init_intreg(&initI.mem0[1]);
|
||||
printf("Int:\n");
|
||||
dump_regs(&initI);
|
||||
|
||||
init_all(&initF32);
|
||||
init_f32reg(&initF32.xmm[10]);
|
||||
init_f32reg(&initF32.xmm[11]);
|
||||
init_f32reg(&initF32.xmm[12]);
|
||||
init_f32reg(&initF32.ymm[10]);
|
||||
init_f32reg(&initF32.ymm[11]);
|
||||
init_f32reg(&initF32.ymm[12]);
|
||||
init_f32reg(&initF32.mem0[1]);
|
||||
initF32.ff = 32;
|
||||
printf("F32:\n");
|
||||
dump_regs(&initF32);
|
||||
|
||||
init_all(&initF64);
|
||||
init_f64reg(&initF64.xmm[10]);
|
||||
init_f64reg(&initF64.xmm[11]);
|
||||
init_f64reg(&initF64.xmm[12]);
|
||||
init_f64reg(&initF64.ymm[10]);
|
||||
init_f64reg(&initF64.ymm[11]);
|
||||
init_f64reg(&initF64.ymm[12]);
|
||||
init_f64reg(&initF64.mem0[1]);
|
||||
initF64.ff = 64;
|
||||
printf("F64:\n");
|
||||
dump_regs(&initF64);
|
||||
|
||||
for (i = 0; i < ARRAY_LEN(gather_mem); i++) {
|
||||
init_intreg(&gather_mem[i]);
|
||||
}
|
||||
|
||||
if (argc > 1) {
|
||||
int n = atoi(argv[1]);
|
||||
run_test(&test_table[n]);
|
||||
|
@ -8,6 +8,7 @@ from fnmatch import fnmatch
|
||||
|
||||
archs = [
|
||||
"SSE", "SSE2", "SSE3", "SSSE3", "SSE4_1", "SSE4_2",
|
||||
"AES", "AVX", "AVX2", "AES+AVX", "VAES+AVX",
|
||||
]
|
||||
|
||||
ignore = set(["FISTTP",
|
||||
@ -42,7 +43,7 @@ imask = {
|
||||
'vROUND[PS][SD]': 0x7,
|
||||
'vSHUFPD': 0x0f,
|
||||
'vSHUFPS': 0xff,
|
||||
'vAESKEYGENASSIST': 0,
|
||||
'vAESKEYGENASSIST': 0xff,
|
||||
'VEXTRACT[FI]128': 0x01,
|
||||
'VINSERT[FI]128': 0x01,
|
||||
'VPBLENDD': 0xff,
|
||||
@ -85,7 +86,7 @@ def mem_w(w):
|
||||
else:
|
||||
raise Exception()
|
||||
|
||||
return t + " PTR 16[rdx]"
|
||||
return t + " PTR 32[rdx]"
|
||||
|
||||
class XMMArg():
|
||||
isxmm = True
|
||||
|
Loading…
x
Reference in New Issue
Block a user