* 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:
commit
61fd710b8d
@ -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
11
configure
vendored
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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],
|
||||
|
@ -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 ||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
|
@ -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')
|
||||
|
@ -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 = []
|
||||
|
@ -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,
|
||||
|
@ -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',
|
||||
|
@ -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
@ -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
@ -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'),
|
||||
|
@ -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],
|
||||
|
@ -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
|
||||
|
@ -188,4 +188,4 @@ gdb-%: %
|
||||
run: $(RUN_TESTS)
|
||||
|
||||
clean:
|
||||
rm -f $(TESTS) *.o
|
||||
rm -f $(TESTS) *.o $(CLEANFILES)
|
||||
|
@ -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
|
||||
|
@ -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
330
tests/tcg/i386/test-avx.c
Normal 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
351
tests/tcg/i386/test-avx.py
Executable 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()
|
@ -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
4658
tests/tcg/i386/x86.csv
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user