* SCSI fixes for Mac OS 9

* Fix CPU reset for x86/KVM nested virtualization state
 * remove feature_not_found() from the configure script
 * Meson cleanups from muon
 * improved i386 TCG tests for BMI and SSE
 * SSE bugfixes
 -----BEGIN PGP SIGNATURE-----
 
 iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmMQ+IQUHHBib256aW5p
 QHJlZGhhdC5jb20ACgkQv/vSX3jHroNofQgArLRlbhua699UyDkTEGGv+gBVRRKg
 qJndTFJp5cvjJo3fNeE1XyZGY0PGLH09ilwHKnGqvn7Bc996ty6zi3sLDC+iT/SO
 cRik6EVgZH/0QseYZijviuz7NklL8so/bgn7sORP9ibRWwiojBzm91emUt4X2l5N
 WOmxLYNIPXR/G8LOSv5Dh4C4WXU3zuaLvTmg/fWPoWTF8P+9LU0gEKUzyk0jMJu4
 hb9lVLXyNbgEcdtK+VewWjsdJcdmF1tMAR94GTmbUdwxbwmATqX8w16jGUbnXPt2
 FZfmjS6CJO90uV7wBA91NnFlrJpWyDn1dKQ+ozpW0ZOAO+wfghpVq7/IRA==
 =VRK4
 -----END PGP SIGNATURE-----

Merge tag 'for-upstream' of https://gitlab.com/bonzini/qemu into staging

* SCSI fixes for Mac OS 9
* Fix CPU reset for x86/KVM nested virtualization state
* remove feature_not_found() from the configure script
* Meson cleanups from muon
* improved i386 TCG tests for BMI and SSE
* SSE bugfixes

# -----BEGIN PGP SIGNATURE-----
#
# iQFIBAABCAAyFiEE8TM4V0tmI4mGbHaCv/vSX3jHroMFAmMQ+IQUHHBib256aW5p
# QHJlZGhhdC5jb20ACgkQv/vSX3jHroNofQgArLRlbhua699UyDkTEGGv+gBVRRKg
# qJndTFJp5cvjJo3fNeE1XyZGY0PGLH09ilwHKnGqvn7Bc996ty6zi3sLDC+iT/SO
# cRik6EVgZH/0QseYZijviuz7NklL8so/bgn7sORP9ibRWwiojBzm91emUt4X2l5N
# WOmxLYNIPXR/G8LOSv5Dh4C4WXU3zuaLvTmg/fWPoWTF8P+9LU0gEKUzyk0jMJu4
# hb9lVLXyNbgEcdtK+VewWjsdJcdmF1tMAR94GTmbUdwxbwmATqX8w16jGUbnXPt2
# FZfmjS6CJO90uV7wBA91NnFlrJpWyDn1dKQ+ozpW0ZOAO+wfghpVq7/IRA==
# =VRK4
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 01 Sep 2022 14:23:00 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: (39 commits)
  target/i386: AVX+AES helpers prep
  target/i386: AVX pclmulqdq prep
  target/i386: Rewrite blendv helpers
  target/i386: Misc AVX helper prep
  target/i386: Destructive FP helpers for AVX
  target/i386: Dot product AVX helper prep
  target/i386: reimplement AVX comparison helpers
  target/i386: Floating point arithmetic helper AVX prep
  target/i386: Destructive vector helpers for AVX
  target/i386: Misc integer AVX helper prep
  target/i386: Rewrite simple integer vector helpers
  target/i386: Rewrite vector shift helper
  target/i386: rewrite destructive 3DNow operations
  target/i386: Add CHECK_NO_VEX
  target/i386: do not cast gen_helper_* function pointers
  target/i386: Add size suffix to vector FP helpers
  target/i386: isolate MMX code more
  target/i386: check SSE table flags instead of hardcoding opcodes
  target/i386: Move 3DNOW decoder
  target/i386: Rework sse_op_table6/7
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2022-09-02 13:24:28 -04:00
commit 61fd710b8d
36 changed files with 7059 additions and 1415 deletions

View file

@ -719,7 +719,11 @@ static void kvm_dirty_ring_mark_page(KVMState *s, uint32_t as_id,
static bool dirty_gfn_is_dirtied(struct kvm_dirty_gfn *gfn)
{
return gfn->flags == KVM_DIRTY_GFN_F_DIRTY;
/*
* Read the flags before the value. Pairs with barrier in
* KVM's kvm_dirty_ring_push() function.
*/
return qatomic_load_acquire(&gfn->flags) == KVM_DIRTY_GFN_F_DIRTY;
}
static void dirty_gfn_set_collected(struct kvm_dirty_gfn *gfn)

11
configure vendored
View file

@ -1468,15 +1468,6 @@ if test "$tcg" = "enabled"; then
git_submodules="$git_submodules tests/fp/berkeley-softfloat-3"
fi
feature_not_found() {
feature=$1
remedy=$2
error_exit "User requested feature $feature" \
"configure was not able to find it." \
"$remedy"
}
# ---
# big/little endian test
cat > $TMPC << EOF
@ -1639,7 +1630,7 @@ else
;;
ucontext)
if test "$ucontext_works" != "yes"; then
feature_not_found "ucontext"
error_exit "'ucontext' backend requested but makecontext not available"
fi
;;
sigaltstack)

View file

@ -99,11 +99,6 @@ developers in checking for system features:
Write a minimal C program main() function to the temporary file
indicated by $TMPC
``feature_not_found $NAME $REMEDY``
Print a message to stderr that the feature $NAME was not available
on the system, suggesting the user try $REMEDY to address the
problem.
``error_exit $MESSAGE $MORE...``
Print $MESSAGE to stderr, followed by $MORE... and then exit from the
configure script with non-zero status

View file

@ -292,7 +292,7 @@ static void do_command_phase(ESPState *s)
esp_fifo_pop_buf(&s->cmdfifo, buf, cmdlen);
current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, s->lun);
s->current_req = scsi_req_new(current_lun, 0, s->lun, buf, s);
s->current_req = scsi_req_new(current_lun, 0, s->lun, buf, cmdlen, s);
datalen = scsi_req_enqueue(s->current_req);
s->ti_size = datalen;
fifo8_reset(&s->cmdfifo);
@ -939,6 +939,11 @@ static void esp_soft_reset(ESPState *s)
esp_hard_reset(s);
}
static void esp_bus_reset(ESPState *s)
{
qbus_reset_all(BUS(&s->bus));
}
static void parent_esp_reset(ESPState *s, int irq, int level)
{
if (level) {
@ -1067,6 +1072,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
break;
case CMD_BUSRESET:
trace_esp_mem_writeb_cmd_bus_reset(val);
esp_bus_reset(s);
if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) {
s->rregs[ESP_RINTR] |= INTR_RST;
esp_raise_irq(s);

View file

@ -864,7 +864,7 @@ static void lsi_do_command(LSIState *s)
s->current = g_new0(lsi_request, 1);
s->current->tag = s->select_tag;
s->current->req = scsi_req_new(dev, s->current->tag, s->current_lun, buf,
s->current);
s->dbc, s->current);
n = scsi_req_enqueue(s->current->req);
if (n) {

View file

@ -1062,7 +1062,7 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
info->inquiry_data[0] = 0x7f; /* Force PQual 0x3, PType 0x1f */
info->vpd_page83[0] = 0x7f;
megasas_setup_inquiry(cmdbuf, 0, sizeof(info->inquiry_data));
cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, sizeof(cmdbuf), cmd);
if (!cmd->req) {
trace_megasas_dcmd_req_alloc_failed(cmd->index,
"PD get info std inquiry");
@ -1080,7 +1080,7 @@ static int megasas_pd_get_info_submit(SCSIDevice *sdev, int lun,
return MFI_STAT_INVALID_STATUS;
} else if (info->inquiry_data[0] != 0x7f && info->vpd_page83[0] == 0x7f) {
megasas_setup_inquiry(cmdbuf, 0x83, sizeof(info->vpd_page83));
cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, cmd);
cmd->req = scsi_req_new(sdev, cmd->index, lun, cmdbuf, sizeof(cmdbuf), cmd);
if (!cmd->req) {
trace_megasas_dcmd_req_alloc_failed(cmd->index,
"PD get info vpd inquiry");
@ -1268,7 +1268,7 @@ static int megasas_ld_get_info_submit(SCSIDevice *sdev, int lun,
cmd->iov_buf = g_malloc0(dcmd_size);
info = cmd->iov_buf;
megasas_setup_inquiry(cdb, 0x83, sizeof(info->vpd_page83));
cmd->req = scsi_req_new(sdev, cmd->index, lun, cdb, cmd);
cmd->req = scsi_req_new(sdev, cmd->index, lun, cdb, sizeof(cdb), cmd);
if (!cmd->req) {
trace_megasas_dcmd_req_alloc_failed(cmd->index,
"LD get info vpd inquiry");
@ -1748,7 +1748,7 @@ static int megasas_handle_scsi(MegasasState *s, MegasasCmd *cmd,
return MFI_STAT_SCSI_DONE_WITH_ERROR;
}
cmd->req = scsi_req_new(sdev, cmd->index, lun_id, cdb, cmd);
cmd->req = scsi_req_new(sdev, cmd->index, lun_id, cdb, cdb_len, cmd);
if (!cmd->req) {
trace_megasas_scsi_req_alloc_failed(
mfi_frame_desc(frame_cmd), target_id, lun_id);
@ -1823,7 +1823,7 @@ static int megasas_handle_io(MegasasState *s, MegasasCmd *cmd, int frame_cmd)
megasas_encode_lba(cdb, lba_start, lba_count, is_write);
cmd->req = scsi_req_new(sdev, cmd->index,
lun_id, cdb, cmd);
lun_id, cdb, cdb_len, cmd);
if (!cmd->req) {
trace_megasas_scsi_req_alloc_failed(
mfi_frame_desc(frame_cmd), target_id, lun_id);

View file

@ -324,7 +324,8 @@ static int mptsas_process_scsi_io_request(MPTSASState *s,
}
req->sreq = scsi_req_new(sdev, scsi_io->MsgContext,
scsi_io->LUN[1], scsi_io->CDB, req);
scsi_io->LUN[1], scsi_io->CDB,
scsi_io->CDBLength, req);
if (req->sreq->cmd.xfer > scsi_io->DataLength) {
goto overrun;

View file

@ -102,15 +102,15 @@ static void scsi_device_unrealize(SCSIDevice *s)
}
int scsi_bus_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf,
void *hba_private)
size_t buf_len, void *hba_private)
{
SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, dev->qdev.parent_bus);
int rc;
assert(cmd->len == 0);
rc = scsi_req_parse_cdb(dev, cmd, buf);
rc = scsi_req_parse_cdb(dev, cmd, buf, buf_len);
if (bus->info->parse_cdb) {
rc = bus->info->parse_cdb(dev, cmd, buf, hba_private);
rc = bus->info->parse_cdb(dev, cmd, buf, buf_len, hba_private);
}
return rc;
}
@ -703,7 +703,7 @@ SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
}
SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
uint8_t *buf, void *hba_private)
uint8_t *buf, size_t buf_len, void *hba_private)
{
SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, d->qdev.parent_bus);
const SCSIReqOps *ops;
@ -712,6 +712,11 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
SCSICommand cmd = { .len = 0 };
int ret;
if (buf_len == 0) {
trace_scsi_req_parse_bad(d->id, lun, tag, 0);
goto invalid_opcode;
}
if ((d->unit_attention.key == UNIT_ATTENTION ||
bus->unit_attention.key == UNIT_ATTENTION) &&
(buf[0] != INQUIRY &&
@ -734,13 +739,14 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
}
if (ops != NULL || !sc->parse_cdb) {
ret = scsi_req_parse_cdb(d, &cmd, buf);
ret = scsi_req_parse_cdb(d, &cmd, buf, buf_len);
} else {
ret = sc->parse_cdb(d, &cmd, buf, hba_private);
ret = sc->parse_cdb(d, &cmd, buf, buf_len, hba_private);
}
if (ret != 0) {
trace_scsi_req_parse_bad(d->id, lun, tag, buf[0]);
invalid_opcode:
req = scsi_req_alloc(&reqops_invalid_opcode, d, tag, lun, hba_private);
} else {
assert(cmd.len != 0);
@ -1308,14 +1314,15 @@ static void scsi_cmd_xfer_mode(SCSICommand *cmd)
}
}
int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf)
int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf,
size_t buf_len)
{
int rc;
int len;
cmd->lba = -1;
len = scsi_cdb_length(buf);
if (len < 0) {
if (len < 0 || len > buf_len) {
return -1;
}
@ -1713,7 +1720,11 @@ static int get_scsi_requests(QEMUFile *f, void *pv, size_t size,
qemu_get_buffer(f, buf, sizeof(buf));
qemu_get_be32s(f, &tag);
qemu_get_be32s(f, &lun);
req = scsi_req_new(s, tag, lun, buf, NULL);
/*
* A too-short CDB would have been rejected by scsi_req_new, so just use
* SCSI_CMD_BUF_SIZE as the CDB length.
*/
req = scsi_req_new(s, tag, lun, buf, sizeof(buf), NULL);
req->retry = (sbyte == 1);
if (bus->info->load_request) {
req->hba_private = bus->info->load_request(f, req);

View file

@ -3030,14 +3030,15 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
}
static int scsi_block_parse_cdb(SCSIDevice *d, SCSICommand *cmd,
uint8_t *buf, void *hba_private)
uint8_t *buf, size_t buf_len,
void *hba_private)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, d);
if (scsi_block_is_passthrough(s, buf)) {
return scsi_bus_parse_cdb(&s->qdev, cmd, buf, hba_private);
return scsi_bus_parse_cdb(&s->qdev, cmd, buf, buf_len, hba_private);
} else {
return scsi_req_parse_cdb(&s->qdev, cmd, buf);
return scsi_req_parse_cdb(&s->qdev, cmd, buf, buf_len);
}
}

View file

@ -791,9 +791,10 @@ static Property scsi_generic_properties[] = {
};
static int scsi_generic_parse_cdb(SCSIDevice *dev, SCSICommand *cmd,
uint8_t *buf, void *hba_private)
uint8_t *buf, size_t buf_len,
void *hba_private)
{
return scsi_bus_parse_cdb(dev, cmd, buf, hba_private);
return scsi_bus_parse_cdb(dev, cmd, buf, buf_len, hba_private);
}
static void scsi_generic_class_initfn(ObjectClass *klass, void *data)

View file

@ -783,6 +783,7 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
union srp_iu *srp = &req_iu(req)->srp;
SCSIDevice *sdev;
int n, lun;
size_t cdb_len = sizeof (srp->cmd.cdb) + (srp->cmd.add_cdb_len & ~3);
if ((srp->cmd.lun == 0 || be64_to_cpu(srp->cmd.lun) == SRP_REPORT_LUNS_WLUN)
&& srp->cmd.cdb[0] == REPORT_LUNS) {
@ -801,7 +802,7 @@ static int vscsi_queue_cmd(VSCSIState *s, vscsi_req *req)
} return 1;
}
req->sreq = scsi_req_new(sdev, req->qtag, lun, srp->cmd.cdb, req);
req->sreq = scsi_req_new(sdev, req->qtag, lun, srp->cmd.cdb, cdb_len, req);
n = scsi_req_enqueue(req->sreq);
trace_spapr_vscsi_queue_cmd(req->qtag, srp->cmd.cdb[0],

View file

@ -622,7 +622,8 @@ static void virtio_scsi_command_complete(SCSIRequest *r, size_t resid)
}
static int virtio_scsi_parse_cdb(SCSIDevice *dev, SCSICommand *cmd,
uint8_t *buf, void *hba_private)
uint8_t *buf, size_t buf_len,
void *hba_private)
{
VirtIOSCSIReq *req = hba_private;
@ -696,7 +697,7 @@ static int virtio_scsi_handle_cmd_req_prepare(VirtIOSCSI *s, VirtIOSCSIReq *req)
virtio_scsi_ctx_check(s, d);
req->sreq = scsi_req_new(d, req->req.cmd.tag,
virtio_scsi_get_lun(req->req.cmd.lun),
req->req.cmd.cdb, req);
req->req.cmd.cdb, vs->cdb_size, req);
if (req->sreq->cmd.mode != SCSI_XFER_NONE
&& (req->sreq->cmd.mode != req->mode ||

View file

@ -730,7 +730,7 @@ pvscsi_process_request_descriptor(PVSCSIState *s,
r->sg.elemAddr = descr->dataAddr;
}
r->sreq = scsi_req_new(d, descr->context, r->lun, descr->cdb, r);
r->sreq = scsi_req_new(d, descr->context, r->lun, descr->cdb, descr->cdbLen, r);
if (r->sreq->cmd.mode == SCSI_XFER_FROM_DEV &&
(descr->flags & PVSCSI_FLAG_CMD_DIR_TODEVICE)) {
r->cmp.hostStatus = BTSTAT_BADMSG;

View file

@ -415,7 +415,7 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p)
cbw.cmd_len, s->data_len);
assert(le32_to_cpu(s->csw.residue) == 0);
s->scsi_len = 0;
s->req = scsi_req_new(scsi_dev, tag, cbw.lun, cbw.cmd, NULL);
s->req = scsi_req_new(scsi_dev, tag, cbw.lun, cbw.cmd, cbw.cmd_len, NULL);
if (s->commandlog) {
scsi_req_print(s->req);
}

View file

@ -71,7 +71,7 @@ typedef struct {
uint8_t reserved_2;
uint64_t lun;
uint8_t cdb[16];
uint8_t add_cdb[1]; /* not supported by QEMU */
uint8_t add_cdb[1];
} QEMU_PACKED uas_iu_command;
typedef struct {
@ -699,6 +699,7 @@ static void usb_uas_command(UASDevice *uas, uas_iu *iu)
UASRequest *req;
uint32_t len;
uint16_t tag = be16_to_cpu(iu->hdr.tag);
size_t cdb_len = sizeof(iu->command.cdb) + iu->command.add_cdb_length;
if (iu->command.add_cdb_length > 0) {
qemu_log_mask(LOG_UNIMP, "additional adb length not yet supported\n");
@ -729,7 +730,7 @@ static void usb_uas_command(UASDevice *uas, uas_iu *iu)
req->req = scsi_req_new(req->dev, req->tag,
usb_uas_get_lun(req->lun),
iu->command.cdb, req);
iu->command.cdb, cdb_len, req);
if (uas->requestlog) {
scsi_req_print(req->req);
}

View file

@ -59,7 +59,7 @@ struct SCSIDeviceClass {
void (*realize)(SCSIDevice *dev, Error **errp);
void (*unrealize)(SCSIDevice *dev);
int (*parse_cdb)(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf,
void *hba_private);
size_t buf_len, void *hba_private);
SCSIRequest *(*alloc_req)(SCSIDevice *s, uint32_t tag, uint32_t lun,
uint8_t *buf, void *hba_private);
void (*unit_attention_reported)(SCSIDevice *s);
@ -122,7 +122,7 @@ struct SCSIBusInfo {
int tcq;
int max_channel, max_target, max_lun;
int (*parse_cdb)(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf,
void *hba_private);
size_t buf_len, void *hba_private);
void (*transfer_data)(SCSIRequest *req, uint32_t arg);
void (*fail)(SCSIRequest *req);
void (*complete)(SCSIRequest *req, size_t residual);
@ -192,14 +192,15 @@ void scsi_legacy_handle_cmdline(void);
SCSIRequest *scsi_req_alloc(const SCSIReqOps *reqops, SCSIDevice *d,
uint32_t tag, uint32_t lun, void *hba_private);
SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
uint8_t *buf, void *hba_private);
uint8_t *buf, size_t buf_len, void *hba_private);
int32_t scsi_req_enqueue(SCSIRequest *req);
SCSIRequest *scsi_req_ref(SCSIRequest *req);
void scsi_req_unref(SCSIRequest *req);
int scsi_bus_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf,
void *hba_private);
int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf);
size_t buf_len, void *hba_private);
int scsi_req_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf,
size_t buf_len);
void scsi_req_build_sense(SCSIRequest *req, SCSISense sense);
void scsi_req_print(SCSIRequest *req);
void scsi_req_continue(SCSIRequest *req);

View file

@ -3408,7 +3408,6 @@ foreach target : target_dirs
target_inc += include_directories('linux-headers', is_system: true)
endif
if target.endswith('-softmmu')
qemu_target_name = 'qemu-system-' + target_name
target_type='system'
t = target_softmmu_arch[target_base_arch].apply(config_target, strict: false)
arch_srcs += t.sources()
@ -3425,7 +3424,6 @@ foreach target : target_dirs
abi = config_target['TARGET_ABI_DIR']
target_type='user'
target_inc += common_user_inc
qemu_target_name = 'qemu-' + target_name
if target_base_arch in target_user_arch
t = target_user_arch[target_base_arch].apply(config_target, strict: false)
arch_srcs += t.sources()

View file

@ -82,9 +82,9 @@ option('tcg', type: 'feature', value: 'enabled',
description: 'TCG support')
option('tcg_interpreter', type: 'boolean', value: false,
description: 'TCG with bytecode interpreter (slow)')
option('cfi', type: 'boolean', value: 'false',
option('cfi', type: 'boolean', value: false,
description: 'Control-Flow Integrity (CFI)')
option('cfi_debug', type: 'boolean', value: 'false',
option('cfi_debug', type: 'boolean', value: false,
description: 'Verbose errors in case of CFI violation')
option('multiprocess', type: 'feature', value: 'auto',
description: 'Out of process device emulation support')

View file

@ -38,7 +38,6 @@ if meson.is_cross_build() or 'CONFIG_XKBCOMMON' not in config_host
else
native_qemu_keymap = qemu_keymap
endif
cp = find_program('cp')
if native_qemu_keymap.found()
t = []

View file

@ -2,7 +2,7 @@ plugin_ldflags = []
# Modules need more symbols than just those in plugins/qemu-plugins.symbols
if not enable_modules
if targetos == 'darwin'
qemu_plugins_symbols_list = configure_file(
configure_file(
input: files('qemu-plugins.symbols'),
output: 'qemu-plugins-ld64.symbols',
capture: true,

View file

@ -68,21 +68,6 @@ if have_system or have_tools
]
endif
qapi_storage_daemon_modules = [
'block-core',
'block-export',
'char',
'common',
'control',
'crypto',
'introspect',
'job',
'qom',
'sockets',
'pragma',
'transaction',
]
qapi_nonmodule_outputs = [
'qapi-introspect.c', 'qapi-introspect.h',
'qapi-types.c', 'qapi-types.h',

View file

@ -1695,6 +1695,30 @@ static void kvm_init_xsave(CPUX86State *env)
env->xsave_buf_len);
}
static void kvm_init_nested_state(CPUX86State *env)
{
struct kvm_vmx_nested_state_hdr *vmx_hdr;
uint32_t size;
if (!env->nested_state) {
return;
}
size = env->nested_state->size;
memset(env->nested_state, 0, size);
env->nested_state->size = size;
if (cpu_has_vmx(env)) {
env->nested_state->format = KVM_STATE_NESTED_FORMAT_VMX;
vmx_hdr = &env->nested_state->hdr.vmx;
vmx_hdr->vmxon_pa = -1ull;
vmx_hdr->vmcs12_pa = -1ull;
} else if (cpu_has_svm(env)) {
env->nested_state->format = KVM_STATE_NESTED_FORMAT_SVM;
}
}
int kvm_arch_init_vcpu(CPUState *cs)
{
struct {
@ -2122,19 +2146,10 @@ int kvm_arch_init_vcpu(CPUState *cs)
assert(max_nested_state_len >= offsetof(struct kvm_nested_state, data));
if (cpu_has_vmx(env) || cpu_has_svm(env)) {
struct kvm_vmx_nested_state_hdr *vmx_hdr;
env->nested_state = g_malloc0(max_nested_state_len);
env->nested_state->size = max_nested_state_len;
if (cpu_has_vmx(env)) {
env->nested_state->format = KVM_STATE_NESTED_FORMAT_VMX;
vmx_hdr = &env->nested_state->hdr.vmx;
vmx_hdr->vmxon_pa = -1ull;
vmx_hdr->vmcs12_pa = -1ull;
} else {
env->nested_state->format = KVM_STATE_NESTED_FORMAT_SVM;
}
kvm_init_nested_state(env);
}
}
@ -2199,6 +2214,8 @@ void kvm_arch_reset_vcpu(X86CPU *cpu)
/* enabled by default */
env->poll_control_msr = 1;
kvm_init_nested_state(env);
sev_es_set_reset_vector(CPU(cpu));
}
@ -4512,6 +4529,18 @@ int kvm_arch_put_registers(CPUState *cpu, int level)
assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
/*
* Put MSR_IA32_FEATURE_CONTROL first, this ensures the VM gets out of VMX
* root operation upon vCPU reset. kvm_put_msr_feature_control() should also
* preceed kvm_put_nested_state() when 'real' nested state is set.
*/
if (level >= KVM_PUT_RESET_STATE) {
ret = kvm_put_msr_feature_control(x86_cpu);
if (ret < 0) {
return ret;
}
}
/* must be before kvm_put_nested_state so that EFER.SVME is set */
ret = has_sregs2 ? kvm_put_sregs2(x86_cpu) : kvm_put_sregs(x86_cpu);
if (ret < 0) {
@ -4523,11 +4552,6 @@ int kvm_arch_put_registers(CPUState *cpu, int level)
if (ret < 0) {
return ret;
}
ret = kvm_put_msr_feature_control(x86_cpu);
if (ret < 0) {
return ret;
}
}
if (level == KVM_PUT_FULL_STATE) {

File diff suppressed because it is too large Load diff

View file

@ -122,8 +122,8 @@ DEF_HELPER_2(glue(movq_mm_T0, SUFFIX), void, Reg, i64)
#if SHIFT == 0
DEF_HELPER_3(glue(pshufw, SUFFIX), void, Reg, Reg, int)
#else
DEF_HELPER_3(shufps, void, Reg, Reg, int)
DEF_HELPER_3(shufpd, void, Reg, Reg, int)
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)
@ -134,9 +134,9 @@ DEF_HELPER_3(glue(pshufhw, SUFFIX), void, Reg, Reg, int)
/* XXX: not accurate */
#define SSE_HELPER_S(name, F) \
DEF_HELPER_3(name ## ps, void, env, Reg, Reg) \
DEF_HELPER_3(glue(name ## ps, SUFFIX), void, env, Reg, Reg) \
DEF_HELPER_3(name ## ss, void, env, Reg, Reg) \
DEF_HELPER_3(name ## pd, void, env, Reg, Reg) \
DEF_HELPER_3(glue(name ## pd, SUFFIX), void, env, Reg, Reg) \
DEF_HELPER_3(name ## sd, void, env, Reg, Reg)
SSE_HELPER_S(add, FPU_ADD)
@ -148,12 +148,12 @@ SSE_HELPER_S(max, FPU_MAX)
SSE_HELPER_S(sqrt, FPU_SQRT)
DEF_HELPER_3(cvtps2pd, void, env, Reg, Reg)
DEF_HELPER_3(cvtpd2ps, void, env, Reg, Reg)
DEF_HELPER_3(glue(cvtps2pd, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(glue(cvtpd2ps, SUFFIX), void, env, Reg, Reg)
DEF_HELPER_3(cvtss2sd, void, env, Reg, Reg)
DEF_HELPER_3(cvtsd2ss, void, env, Reg, Reg)
DEF_HELPER_3(cvtdq2ps, void, env, Reg, Reg)
DEF_HELPER_3(cvtdq2pd, 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(cvtpi2ps, void, env, ZMMReg, MMXReg)
DEF_HELPER_3(cvtpi2pd, void, env, ZMMReg, MMXReg)
DEF_HELPER_3(cvtsi2ss, void, env, ZMMReg, i32)
@ -164,8 +164,8 @@ DEF_HELPER_3(cvtsq2ss, void, env, ZMMReg, i64)
DEF_HELPER_3(cvtsq2sd, void, env, ZMMReg, i64)
#endif
DEF_HELPER_3(cvtps2dq, void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(cvtpd2dq, void, env, ZMMReg, ZMMReg)
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 +175,8 @@ DEF_HELPER_2(cvtss2sq, s64, env, ZMMReg)
DEF_HELPER_2(cvtsd2sq, s64, env, ZMMReg)
#endif
DEF_HELPER_3(cvttps2dq, void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(cvttpd2dq, void, env, ZMMReg, ZMMReg)
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)
@ -186,42 +186,42 @@ DEF_HELPER_2(cvttss2sq, s64, env, ZMMReg)
DEF_HELPER_2(cvttsd2sq, s64, env, ZMMReg)
#endif
DEF_HELPER_3(rsqrtps, void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(glue(rsqrtps, SUFFIX), void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(rsqrtss, void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(rcpps, void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(glue(rcpps, SUFFIX), void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(rcpss, void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(extrq_r, void, env, ZMMReg, ZMMReg)
DEF_HELPER_4(extrq_i, void, env, ZMMReg, int, int)
DEF_HELPER_3(insertq_r, void, env, ZMMReg, ZMMReg)
DEF_HELPER_4(insertq_i, void, env, ZMMReg, int, int)
DEF_HELPER_3(haddps, void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(haddpd, void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(hsubps, void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(hsubpd, void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(addsubps, void, env, ZMMReg, ZMMReg)
DEF_HELPER_3(addsubpd, void, env, ZMMReg, ZMMReg)
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)
#define SSE_HELPER_CMP(name, F) \
DEF_HELPER_3(name ## ps, void, env, Reg, Reg) \
DEF_HELPER_3(name ## ss, void, env, Reg, Reg) \
DEF_HELPER_3(name ## pd, void, env, Reg, Reg) \
#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_CMP(cmpeq, FPU_CMPEQ)
SSE_HELPER_CMP(cmplt, FPU_CMPLT)
SSE_HELPER_CMP(cmple, FPU_CMPLE)
SSE_HELPER_CMP(cmpunord, FPU_CMPUNORD)
SSE_HELPER_CMP(cmpneq, FPU_CMPNEQ)
SSE_HELPER_CMP(cmpnlt, FPU_CMPNLT)
SSE_HELPER_CMP(cmpnle, FPU_CMPNLE)
SSE_HELPER_CMP(cmpord, FPU_CMPORD)
SSE_HELPER_CMP(cmpeq, FPU_CMPQ, FPU_EQ)
SSE_HELPER_CMP(cmplt, FPU_CMPS, FPU_LT)
SSE_HELPER_CMP(cmple, FPU_CMPS, FPU_LE)
SSE_HELPER_CMP(cmpunord, FPU_CMPQ, FPU_UNORD)
SSE_HELPER_CMP(cmpneq, FPU_CMPQ, !FPU_EQ)
SSE_HELPER_CMP(cmpnlt, FPU_CMPS, !FPU_LT)
SSE_HELPER_CMP(cmpnle, FPU_CMPS, !FPU_LE)
SSE_HELPER_CMP(cmpord, FPU_CMPQ, !FPU_UNORD)
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)
DEF_HELPER_2(movmskps, i32, env, Reg)
DEF_HELPER_2(movmskpd, i32, env, Reg)
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)

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,4 @@
# FIXME extra_args should accept files()
dir = meson.current_source_dir()
gen = [
decodetree.process('insn16.decode', extra_args: ['--static-decode=decode_insn16', '--insnwidth=16']),
decodetree.process('insn32.decode', extra_args: '--static-decode=decode_insn32'),

View file

@ -632,7 +632,7 @@ test('fp-test-mulAdd', fptest,
['f16_mulAdd', 'f32_mulAdd', 'f64_mulAdd', 'f128_mulAdd'],
suite: ['softfloat-slow', 'softfloat-ops-slow', 'slow'], timeout: 90)
fpbench = executable(
executable(
'fp-bench',
['fp-bench.c', '../../fpu/softfloat.c'],
link_with: [libtestfloat, libsoftfloat],

View file

@ -215,18 +215,18 @@ test('QAPI schema regression tests', python,
diff = find_program('diff')
qapi_doc = custom_target('QAPI doc',
output: ['doc-good-qapi-commands.c', 'doc-good-qapi-commands.h',
'doc-good-qapi-emit-events.c', 'doc-good-qapi-emit-events.h',
'doc-good-qapi-events.c', 'doc-good-qapi-events.h',
'doc-good-qapi-init-commands.c', 'doc-good-qapi-init-commands.h',
'doc-good-qapi-introspect.c', 'doc-good-qapi-introspect.h',
'doc-good-qapi-types.c', 'doc-good-qapi-types.h',
'doc-good-qapi-visit.c', 'doc-good-qapi-visit.h' ],
input: files('doc-good.json'),
command: [ qapi_gen, '-o', meson.current_build_dir(),
'-p', 'doc-good-', '@INPUT0@' ],
depend_files: qapi_gen_depends)
custom_target('QAPI doc',
output: ['doc-good-qapi-commands.c', 'doc-good-qapi-commands.h',
'doc-good-qapi-emit-events.c', 'doc-good-qapi-emit-events.h',
'doc-good-qapi-events.c', 'doc-good-qapi-events.h',
'doc-good-qapi-init-commands.c', 'doc-good-qapi-init-commands.h',
'doc-good-qapi-introspect.c', 'doc-good-qapi-introspect.h',
'doc-good-qapi-types.c', 'doc-good-qapi-types.h',
'doc-good-qapi-visit.c', 'doc-good-qapi-visit.h' ],
input: files('doc-good.json'),
command: [ qapi_gen, '-o', meson.current_build_dir(),
'-p', 'doc-good-', '@INPUT0@' ],
depend_files: qapi_gen_depends)
if build_docs
# Test the document-comment document generation code by running a test schema

View file

@ -188,4 +188,4 @@ gdb-%: %
run: $(RUN_TESTS)
clean:
rm -f $(TESTS) *.o
rm -f $(TESTS) *.o $(CLEANFILES)

View file

@ -7,8 +7,8 @@ VPATH += $(I386_SRC)
I386_SRCS=$(notdir $(wildcard $(I386_SRC)/*.c))
ALL_X86_TESTS=$(I386_SRCS:.c=)
SKIP_I386_TESTS=test-i386-ssse3
X86_64_TESTS:=$(filter test-i386-ssse3, $(ALL_X86_TESTS))
SKIP_I386_TESTS=test-i386-ssse3 test-avx
X86_64_TESTS:=$(filter test-i386-bmi2 test-i386-ssse3 test-avx, $(ALL_X86_TESTS))
test-i386-sse-exceptions: CFLAGS += -msse4.1 -mfpmath=sse
run-test-i386-sse-exceptions: QEMU_OPTS += -cpu max
@ -18,6 +18,7 @@ test-i386-pcmpistri: CFLAGS += -msse4.2
run-test-i386-pcmpistri: QEMU_OPTS += -cpu max
run-plugin-test-i386-pcmpistri-%: QEMU_OPTS += -cpu max
test-i386-bmi2: CFLAGS=-O2
run-test-i386-bmi2: QEMU_OPTS += -cpu max
run-plugin-test-i386-bmi2-%: QEMU_OPTS += -cpu max
@ -80,3 +81,10 @@ run-sha512-sse: QEMU_OPTS+=-cpu max
run-plugin-sha512-sse-with-%: QEMU_OPTS+=-cpu max
TESTS+=sha512-sse
CLEANFILES += test-avx.h
test-avx.h: test-avx.py x86.csv
$(PYTHON) $(I386_SRC)/test-avx.py $(I386_SRC)/x86.csv $@
test-avx: CFLAGS += -masm=intel -O -I.
test-avx: test-avx.h

View file

@ -15,6 +15,15 @@ The Linux system call vm86() is used to test vm86 emulation.
Various exceptions are raised to test most of the x86 user space
exception reporting.
test-avx
--------
This program executes most SSE/AVX instructions and generates a text output,
for comparison with the output obtained with a real CPU or another emulator.
test-avx.h is generate from x86.csv by test-avx.py
x86.csv comes from https://github.com/quasilyte/avx512test
linux-test
----------

330
tests/tcg/i386/test-avx.c Normal file
View file

@ -0,0 +1,330 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
typedef void (*testfn)(void);
typedef struct {
uint64_t q0, q1;
} __attribute__((aligned(16))) v2di;
typedef struct {
uint64_t mm[8];
v2di xmm[16];
uint64_t r[16];
uint64_t flags;
uint32_t ff;
uint64_t pad;
v2di mem[4];
v2di mem0[4];
} reg_state;
typedef struct {
int n;
testfn fn;
const char *s;
reg_state *init;
} TestDef;
reg_state initI;
reg_state initF32;
reg_state initF64;
static void dump_xmm(const char *name, int n, const v2di *r, int ff)
{
printf("%s%d = %016lx %016lx\n",
name, n, r->q1, r->q0);
if (ff == 64) {
double v[2];
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",
v[3], v[2], v[1], v[0]);
}
}
static void dump_regs(reg_state *s)
{
int i;
for (i = 0; i < 16; i++) {
dump_xmm("xmm", i, &s->xmm[i], 0);
}
for (i = 0; i < 4; i++) {
dump_xmm("mem", i, &s->mem0[i], 0);
}
}
static void compare_state(const reg_state *a, const reg_state *b)
{
int i;
for (i = 0; i < 8; i++) {
if (a->mm[i] != b->mm[i]) {
printf("MM%d = %016lx\n", i, b->mm[i]);
}
}
for (i = 0; i < 16; i++) {
if (a->r[i] != b->r[i]) {
printf("r%d = %016lx\n", i, b->r[i]);
}
}
for (i = 0; i < 16; i++) {
if (memcmp(&a->xmm[i], &b->xmm[i], 16)) {
dump_xmm("xmm", i, &b->xmm[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 (a->flags != b->flags) {
printf("FLAGS = %016lx\n", b->flags);
}
}
#define LOADMM(r, o) "movq " #r ", " #o "[%0]\n\t"
#define LOADXMM(r, o) "movdqa " #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 MMREG(F) \
F(mm0, 0x00) \
F(mm1, 0x08) \
F(mm2, 0x10) \
F(mm3, 0x18) \
F(mm4, 0x20) \
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 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) \
static void run_test(const TestDef *t)
{
reg_state result;
reg_state *init = t->init;
memcpy(init->mem, init->mem0, sizeof(init->mem));
printf("%5d %s\n", t->n, t->s);
asm volatile(
MMREG(LOADMM)
XMMREG(LOADXMM)
"sub rsp, 128\n\t"
"push rax\n\t"
"push rbx\n\t"
"push rcx\n\t"
"push rdx\n\t"
"push %1\n\t"
"push %2\n\t"
"mov rax, %0\n\t"
"pushf\n\t"
"pop rbx\n\t"
"shr rbx, 8\n\t"
"shl rbx, 8\n\t"
"mov rcx, 0x1c0[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"
"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 rbx, 0\n\t"
"mov 0x170[rax], rbx\n\t"
"mov 0x178[rax], rbx\n\t"
"pushf\n\t"
"pop rbx\n\t"
"and rbx, 0xff\n\t"
"mov 0x1c0[rax], rbx\n\t"
"add rsp, 16\n\t"
"pop rdx\n\t"
"pop rcx\n\t"
"pop rbx\n\t"
"pop rax\n\t"
"add rsp, 128\n\t"
MMREG(STOREMM)
XMMREG(STOREXMM)
: : "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"
);
compare_state(init, &result);
}
#define TEST(n, cmd, type) \
static void __attribute__((naked)) test_##n(void) \
{ \
asm volatile(cmd); \
asm volatile("ret"); \
}
#include "test-avx.h"
static const TestDef test_table[] = {
#define TEST(n, cmd, type) {n, test_##n, cmd, &init##type},
#include "test-avx.h"
{-1, NULL, "", NULL}
};
static void run_all(void)
{
const TestDef *t;
for (t = test_table; t->fn; t++) {
run_test(t);
}
}
#define ARRAY_LEN(x) (sizeof(x) / sizeof(x[0]))
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},
};
v2di deadbeef = {0xa5a5a5a5deadbeefull, 0xa5a5a5a5deadbeefull};
v2di indexq = {0x000000000000001full, 0x000000000000008full};
v2di indexd = {0x00000002000000efull, 0xfffffff500000010ull};
void init_f32reg(v2di *r)
{
static int n;
float v[4];
int i;
for (i = 0; i < 4; i++) {
v[i] = val_f32[n++];
if (n == ARRAY_LEN(val_f32)) {
n = 0;
}
}
memcpy(r, v, sizeof(*r));
}
void init_f64reg(v2di *r)
{
static int n;
double v[2];
int i;
for (i = 0; i < 2; i++) {
v[i] = val_f64[n++];
if (n == ARRAY_LEN(val_f64)) {
n = 0;
}
}
memcpy(r, v, sizeof(*r));
}
void init_intreg(v2di *r)
{
static uint64_t mask;
static int n;
r->q0 = val_i64[n].q0 ^ mask;
r->q1 = val_i64[n].q1 ^ mask;
n++;
if (n == ARRAY_LEN(val_i64)) {
n = 0;
mask *= 0x104C11DB7;
}
}
static void init_all(reg_state *s)
{
int i;
s->r[3] = (uint64_t)&s->mem[0]; /* rdx */
s->r[5] = (uint64_t)&s->mem[2]; /* rdi */
s->flags = 2;
for (i = 0; i < 8; i++) {
s->xmm[i] = deadbeef;
}
s->xmm[13] = indexd;
s->xmm[14] = indexq;
for (i = 0; i < 2; i++) {
s->mem0[i] = deadbeef;
}
}
int main(int argc, char *argv[])
{
init_all(&initI);
init_intreg(&initI.xmm[10]);
init_intreg(&initI.xmm[11]);
init_intreg(&initI.xmm[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.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.mem0[1]);
initF64.ff = 64;
printf("F64:\n");
dump_regs(&initF64);
if (argc > 1) {
int n = atoi(argv[1]);
run_test(&test_table[n]);
} else {
run_all();
}
return 0;
}

351
tests/tcg/i386/test-avx.py Executable file
View file

@ -0,0 +1,351 @@
#! /usr/bin/env python3
# Generate test-avx.h from x86.csv
import csv
import sys
from fnmatch import fnmatch
archs = [
# TODO: MMX?
"SSE", "SSE2", "SSE3", "SSSE3", "SSE4_1", "SSE4_2",
]
ignore = set(["FISTTP",
"LDMXCSR", "VLDMXCSR", "STMXCSR", "VSTMXCSR"])
imask = {
'vBLENDPD': 0xff,
'vBLENDPS': 0x0f,
'CMP[PS][SD]': 0x07,
'VCMP[PS][SD]': 0x1f,
'vDPPD': 0x33,
'vDPPS': 0xff,
'vEXTRACTPS': 0x03,
'vINSERTPS': 0xff,
'MPSADBW': 0x7,
'VMPSADBW': 0x3f,
'vPALIGNR': 0x3f,
'vPBLENDW': 0xff,
'vPCMP[EI]STR*': 0x0f,
'vPEXTRB': 0x0f,
'vPEXTRW': 0x07,
'vPEXTRD': 0x03,
'vPEXTRQ': 0x01,
'vPINSRB': 0x0f,
'vPINSRW': 0x07,
'vPINSRD': 0x03,
'vPINSRQ': 0x01,
'vPSHUF[DW]': 0xff,
'vPSHUF[LH]W': 0xff,
'vPS[LR][AL][WDQ]': 0x3f,
'vPS[RL]LDQ': 0x1f,
'vROUND[PS][SD]': 0x7,
'vSHUFPD': 0x0f,
'vSHUFPS': 0xff,
'vAESKEYGENASSIST': 0,
'VEXTRACT[FI]128': 0x01,
'VINSERT[FI]128': 0x01,
'VPBLENDD': 0xff,
'VPERM2[FI]128': 0x33,
'VPERMPD': 0xff,
'VPERMQ': 0xff,
'VPERMILPS': 0xff,
'VPERMILPD': 0x0f,
}
def strip_comments(x):
for l in x:
if l != '' and l[0] != '#':
yield l
def reg_w(w):
if w == 8:
return 'al'
elif w == 16:
return 'ax'
elif w == 32:
return 'eax'
elif w == 64:
return 'rax'
raise Exception("bad reg_w %d" % w)
def mem_w(w):
if w == 8:
t = "BYTE"
elif w == 16:
t = "WORD"
elif w == 32:
t = "DWORD"
elif w == 64:
t = "QWORD"
elif w == 128:
t = "XMMWORD"
elif w == 256:
t = "YMMWORD"
else:
raise Exception()
return t + " PTR 16[rdx]"
class XMMArg():
isxmm = True
def __init__(self, reg, mw):
if mw not in [0, 8, 16, 32, 64, 128, 256]:
raise Exception("Bad /m width: %s" % w)
self.reg = reg
self.mw = mw
self.ismem = mw != 0
def regstr(self, n):
if n < 0:
return mem_w(self.mw)
else:
return "%smm%d" % (self.reg, n)
class MMArg():
isxmm = True
ismem = False # TODO
def regstr(self, n):
return "mm%d" % (n & 7)
def match(op, pattern):
if pattern[0] == 'v':
return fnmatch(op, pattern[1:]) or fnmatch(op, 'V'+pattern[1:])
return fnmatch(op, pattern)
class ArgVSIB():
isxmm = True
ismem = False
def __init__(self, reg, w):
if w not in [32, 64]:
raise Exception("Bad vsib width: %s" % w)
self.w = w
self.reg = reg
def regstr(self, n):
reg = "%smm%d" % (self.reg, n >> 2)
return "[rsi + %s * %d]" % (reg, 1 << (n & 3))
class ArgImm8u():
isxmm = False
ismem = False
def __init__(self, op):
for k, v in imask.items():
if match(op, k):
self.mask = imask[k];
return
raise Exception("Unknown immediate")
def vals(self):
mask = self.mask
yield 0
n = 0
while n != mask:
n += 1
while (n & ~mask) != 0:
n += (n & ~mask)
yield n
class ArgRM():
isxmm = False
def __init__(self, rw, mw):
if rw not in [8, 16, 32, 64]:
raise Exception("Bad r/w width: %s" % w)
if mw not in [0, 8, 16, 32, 64]:
raise Exception("Bad r/w width: %s" % w)
self.rw = rw
self.mw = mw
self.ismem = mw != 0
def regstr(self, n):
if n < 0:
return mem_w(self.mw)
else:
return reg_w(self.rw)
class ArgMem():
isxmm = False
ismem = True
def __init__(self, w):
if w not in [8, 16, 32, 64, 128, 256]:
raise Exception("Bad mem width: %s" % w)
self.w = w
def regstr(self, n):
return mem_w(self.w)
def ArgGenerator(arg, op):
if arg[:3] == 'xmm' or arg[:3] == "ymm":
if "/" in arg:
r, m = arg.split('/')
if (m[0] != 'm'):
raise Exception("Expected /m: %s", arg)
return XMMArg(arg[0], int(m[1:]));
else:
return XMMArg(arg[0], 0);
elif arg[:2] == 'mm':
return MMArg();
elif arg[:4] == 'imm8':
return ArgImm8u(op);
elif arg == '<XMM0>':
return None
elif arg[0] == 'r':
if '/m' in arg:
r, m = arg.split('/')
if (m[0] != 'm'):
raise Exception("Expected /m: %s", arg)
mw = int(m[1:])
if r == 'r':
rw = mw
else:
rw = int(r[1:])
return ArgRM(rw, mw)
return ArgRM(int(arg[1:]), 0);
elif arg[0] == 'm':
return ArgMem(int(arg[1:]))
elif arg[:2] == 'vm':
return ArgVSIB(arg[-1], int(arg[2:-1]))
else:
raise Exception("Unrecognised arg: %s", arg)
class InsnGenerator:
def __init__(self, op, args):
self.op = op
if op[-2:] in ["PS", "PD", "SS", "SD"]:
if op[-1] == 'S':
self.optype = 'F32'
else:
self.optype = 'F64'
else:
self.optype = 'I'
try:
self.args = list(ArgGenerator(a, op) for a in args)
if len(self.args) > 0 and self.args[-1] is None:
self.args = self.args[:-1]
except Exception as e:
raise Exception("Bad arg %s: %s" % (op, e))
def gen(self):
regs = (10, 11, 12)
dest = 9
nreg = len(self.args)
if nreg == 0:
yield self.op
return
if isinstance(self.args[-1], ArgImm8u):
nreg -= 1
immarg = self.args[-1]
else:
immarg = None
memarg = -1
for n, arg in enumerate(self.args):
if arg.ismem:
memarg = n
if (self.op.startswith("VGATHER") or self.op.startswith("VPGATHER")):
if "GATHERD" in self.op:
ireg = 13 << 2
else:
ireg = 14 << 2
regset = [
(dest, ireg | 0, regs[0]),
(dest, ireg | 1, regs[0]),
(dest, ireg | 2, regs[0]),
(dest, ireg | 3, regs[0]),
]
if memarg >= 0:
raise Exception("vsib with memory: %s" % self.op)
elif nreg == 1:
regset = [(regs[0],)]
if memarg == 0:
regset += [(-1,)]
elif nreg == 2:
regset = [
(regs[0], regs[1]),
(regs[0], regs[0]),
]
if memarg == 0:
regset += [(-1, regs[0])]
elif memarg == 1:
regset += [(dest, -1)]
elif nreg == 3:
regset = [
(dest, regs[0], regs[1]),
(dest, regs[0], regs[0]),
(regs[0], regs[0], regs[1]),
(regs[0], regs[1], regs[0]),
(regs[0], regs[0], regs[0]),
]
if memarg == 2:
regset += [
(dest, regs[0], -1),
(regs[0], regs[0], -1),
]
elif memarg > 0:
raise Exception("Memarg %d" % memarg)
elif nreg == 4:
regset = [
(dest, regs[0], regs[1], regs[2]),
(dest, regs[0], regs[0], regs[1]),
(dest, regs[0], regs[1], regs[0]),
(dest, regs[1], regs[0], regs[0]),
(dest, regs[0], regs[0], regs[0]),
(regs[0], regs[0], regs[1], regs[2]),
(regs[0], regs[1], regs[0], regs[2]),
(regs[0], regs[1], regs[2], regs[0]),
(regs[0], regs[0], regs[0], regs[1]),
(regs[0], regs[0], regs[1], regs[0]),
(regs[0], regs[1], regs[0], regs[0]),
(regs[0], regs[0], regs[0], regs[0]),
]
if memarg == 2:
regset += [
(dest, regs[0], -1, regs[1]),
(dest, regs[0], -1, regs[0]),
(regs[0], regs[0], -1, regs[1]),
(regs[0], regs[1], -1, regs[0]),
(regs[0], regs[0], -1, regs[0]),
]
elif memarg > 0:
raise Exception("Memarg4 %d" % memarg)
else:
raise Exception("Too many regs: %s(%d)" % (self.op, nreg))
for regv in regset:
argstr = []
for i in range(nreg):
arg = self.args[i]
argstr.append(arg.regstr(regv[i]))
if immarg is None:
yield self.op + ' ' + ','.join(argstr)
else:
for immval in immarg.vals():
yield self.op + ' ' + ','.join(argstr) + ',' + str(immval)
def split0(s):
if s == '':
return []
return s.split(',')
def main():
n = 0
if len(sys.argv) != 3:
print("Usage: test-avx.py x86.csv test-avx.h")
exit(1)
csvfile = open(sys.argv[1], 'r', newline='')
with open(sys.argv[2], "w") as outf:
outf.write("// Generated by test-avx.py. Do not edit.\n")
for row in csv.reader(strip_comments(csvfile)):
insn = row[0].replace(',', '').split()
if insn[0] in ignore:
continue
cpuid = row[6]
if cpuid in archs:
g = InsnGenerator(insn[0], insn[1:])
for insn in g.gen():
outf.write('TEST(%d, "%s", %s)\n' % (n, insn, g.optype))
n += 1
outf.write("#undef TEST\n")
csvfile.close()
if __name__ == "__main__":
main()

View file

@ -1,6 +1,66 @@
/* See if various BMI2 instructions give expected results */
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#define insn1q(name, arg0) \
static inline uint64_t name##q(uint64_t arg0) \
{ \
uint64_t result64; \
asm volatile (#name "q %1, %0" : "=r"(result64) : "rm"(arg0)); \
return result64; \
}
#define insn1l(name, arg0) \
static inline uint32_t name##l(uint32_t arg0) \
{ \
uint32_t result32; \
asm volatile (#name "l %k1, %k0" : "=r"(result32) : "rm"(arg0)); \
return result32; \
}
#define insn2q(name, arg0, c0, arg1, c1) \
static inline uint64_t name##q(uint64_t arg0, uint64_t arg1) \
{ \
uint64_t result64; \
asm volatile (#name "q %2, %1, %0" : "=r"(result64) : c0(arg0), c1(arg1)); \
return result64; \
}
#define insn2l(name, arg0, c0, arg1, c1) \
static inline uint32_t name##l(uint32_t arg0, uint32_t arg1) \
{ \
uint32_t result32; \
asm volatile (#name "l %k2, %k1, %k0" : "=r"(result32) : c0(arg0), c1(arg1)); \
return result32; \
}
#ifdef __x86_64
insn2q(pext, src, "r", mask, "rm")
insn2q(pdep, src, "r", mask, "rm")
insn2q(andn, clear, "rm", val, "r")
insn2q(bextr, range, "rm", val, "r")
insn2q(bzhi, pos, "rm", val, "r")
insn2q(rorx, val, "r", n, "i")
insn2q(sarx, val, "rm", n, "r")
insn2q(shlx, val, "rm", n, "r")
insn2q(shrx, val, "rm", n, "r")
insn1q(blsi, src)
insn1q(blsmsk, src)
insn1q(blsr, src)
#endif
insn2l(pext, src, "r", mask, "rm")
insn2l(pdep, src, "r", mask, "rm")
insn2l(andn, clear, "rm", val, "r")
insn2l(bextr, range, "rm", val, "r")
insn2l(bzhi, pos, "rm", val, "r")
insn2l(rorx, val, "r", n, "i")
insn2l(sarx, val, "rm", n, "r")
insn2l(shlx, val, "rm", n, "r")
insn2l(shrx, val, "rm", n, "r")
insn1l(blsi, src)
insn1l(blsmsk, src)
insn1l(blsr, src)
int main(int argc, char *argv[]) {
uint64_t ehlo = 0x202020204f4c4845ull;
@ -11,32 +71,125 @@ int main(int argc, char *argv[]) {
uint64_t result64;
/* 64 bits */
asm volatile ("pextq %2, %1, %0" : "=r"(result64) : "r"(ehlo), "m"(mask));
result64 = andnq(mask, ehlo);
assert(result64 == 0x002020204d4c4844);
result64 = pextq(ehlo, mask);
assert(result64 == 133);
asm volatile ("pdepq %2, %1, %0" : "=r"(result64) : "r"(result64), "m"(mask));
result64 = pdepq(result64, mask);
assert(result64 == (ehlo & mask));
asm volatile ("pextq %2, %1, %0" : "=r"(result64) : "r"(-1ull), "m"(mask));
result64 = pextq(-1ull, mask);
assert(result64 == 511); /* mask has 9 bits set */
asm volatile ("pdepq %2, %1, %0" : "=r"(result64) : "r"(-1ull), "m"(mask));
result64 = pdepq(-1ull, mask);
assert(result64 == mask);
result64 = bextrq(mask, 0x3f00);
assert(result64 == (mask & ~INT64_MIN));
result64 = bextrq(mask, 0x1038);
assert(result64 == 0xa0);
result64 = bextrq(mask, 0x10f8);
assert(result64 == 0);
result64 = blsiq(0x30);
assert(result64 == 0x10);
result64 = blsiq(0x30ull << 32);
assert(result64 == 0x10ull << 32);
result64 = blsmskq(0x30);
assert(result64 == 0x1f);
result64 = blsrq(0x30);
assert(result64 == 0x20);
result64 = blsrq(0x30ull << 32);
assert(result64 == 0x20ull << 32);
result64 = bzhiq(mask, 0x3f);
assert(result64 == (mask & ~INT64_MIN));
result64 = bzhiq(mask, 0x1f);
assert(result64 == (mask & ~(-1 << 30)));
result64 = rorxq(0x2132435465768798, 8);
assert(result64 == 0x9821324354657687);
result64 = sarxq(0xffeeddccbbaa9988, 8);
assert(result64 == 0xffffeeddccbbaa99);
result64 = sarxq(0x77eeddccbbaa9988, 8 | 64);
assert(result64 == 0x0077eeddccbbaa99);
result64 = shrxq(0xffeeddccbbaa9988, 8);
assert(result64 == 0x00ffeeddccbbaa99);
result64 = shrxq(0x77eeddccbbaa9988, 8 | 192);
assert(result64 == 0x0077eeddccbbaa99);
result64 = shlxq(0xffeeddccbbaa9988, 8);
assert(result64 == 0xeeddccbbaa998800);
#endif
/* 32 bits */
asm volatile ("pextl %2, %k1, %k0" : "=r"(result32) : "r"((uint32_t) ehlo), "m"(mask));
result32 = andnl(mask, ehlo);
assert(result32 == 0x04d4c4844);
result32 = pextl((uint32_t) ehlo, mask);
assert(result32 == 5);
asm volatile ("pdepl %2, %k1, %k0" : "=r"(result32) : "r"(result32), "m"(mask));
result32 = pdepl(result32, mask);
assert(result32 == (uint32_t)(ehlo & mask));
asm volatile ("pextl %2, %k1, %k0" : "=r"(result32) : "r"(-1ull), "m"(mask));
result32 = pextl(-1u, mask);
assert(result32 == 7); /* mask has 3 bits set */
asm volatile ("pdepl %2, %k1, %k0" : "=r"(result32) : "r"(-1ull), "m"(mask));
result32 = pdepl(-1u, mask);
assert(result32 == (uint32_t)mask);
result32 = bextrl(mask, 0x1f00);
assert(result32 == (mask & ~INT32_MIN));
result32 = bextrl(ehlo, 0x1018);
assert(result32 == 0x4f);
result32 = bextrl(mask, 0x1038);
assert(result32 == 0);
result32 = blsil(0xffff);
assert(result32 == 1);
result32 = blsmskl(0x300);
assert(result32 == 0x1ff);
result32 = blsrl(0xffc);
assert(result32 == 0xff8);
result32 = bzhil(mask, 0xf);
assert(result32 == 1);
result32 = rorxl(0x65768798, 8);
assert(result32 == 0x98657687);
result32 = sarxl(0xffeeddcc, 8);
assert(result32 == 0xffffeedd);
result32 = sarxl(0x77eeddcc, 8 | 32);
assert(result32 == 0x0077eedd);
result32 = shrxl(0xffeeddcc, 8);
assert(result32 == 0x00ffeedd);
result32 = shrxl(0x77eeddcc, 8 | 128);
assert(result32 == 0x0077eedd);
result32 = shlxl(0xffeeddcc, 8);
assert(result32 == 0xeeddcc00);
return 0;
}

4658
tests/tcg/i386/x86.csv Normal file

File diff suppressed because it is too large Load diff

View file

@ -14,7 +14,10 @@ TESTS=$(MULTIARCH_TESTS) $(X86_64_TESTS) test-x86_64
else
TESTS=$(MULTIARCH_TESTS)
endif
QEMU_OPTS += -cpu max
run-test-i386-ssse3: QEMU_OPTS += -cpu max
run-test-avx: QEMU_OPTS += -cpu max
run-plugin-test-i386-ssse3-%: QEMU_OPTS += -cpu max
test-x86_64: LDFLAGS+=-lm -lc
test-x86_64: test-i386.c test-i386.h test-i386-shift.h test-i386-muldiv.h