* 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>
master
Stefan Hajnoczi 2022-10-18 11:14:31 -04:00
commit 214a8da236
32 changed files with 5978 additions and 2929 deletions

55
configure vendored
View File

@ -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=$?

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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)

View File

@ -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 */

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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:

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -625,12 +625,12 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_POPCNT | \
CPUID_EXT_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;

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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));

View File

@ -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;

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

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

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

File diff suppressed because it is too large Load Diff

View File

@ -2559,6 +2559,22 @@ static void do_xsave_sse(CPUX86State *env, target_ulong ptr, uintptr_t ra)
}
}
static void do_xsave_ymmh(CPUX86State *env, target_ulong ptr, uintptr_t ra)
{
int i, nb_xmm_regs;
if (env->hflags & HF_CS64_MASK) {
nb_xmm_regs = 16;
} else {
nb_xmm_regs = 8;
}
for (i = 0; i < nb_xmm_regs; i++, ptr += 16) {
cpu_stq_data_ra(env, ptr, env->xmm_regs[i].ZMM_Q(2), ra);
cpu_stq_data_ra(env, ptr + 8, env->xmm_regs[i].ZMM_Q(3), ra);
}
}
static void do_xsave_bndregs(CPUX86State *env, target_ulong ptr, uintptr_t ra)
{
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"

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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]);

View File

@ -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